[AmateursCTF 2023] 太难了

随着大学放假,基本上周末也没什么比赛了,国外的小比赛难度没准儿。这个周末太受打击了。

crypto题只作了一半

Crypto

5,Compact XORs

第1天出来的5个题只有这一个巨简单,其它都巨难

610c6115651072014317463d73127613732c73036102653a6217742b701c61086e1a651d742b69075f2f6c0d69075f2c690e681c5f673604650364023944
616d6174657572734354467b

题目只给出一个串,显然单数字符是正确的,偶字节就得猜了,这个也没难度,就是偶异或一下奇数位,虽然没有难度,但这题还真是头回见。

#2,4偶数位是是1,3奇数位的异或
a = bytes.fromhex('610c6115651072014317463d73127613732c73036102653a6217742b701c61086e1a651d742b69075f2f6c0d69075f2c690e681c5f673604650364023944')
for i in range(0,len(a),2):
     print(chr(a[i])+chr(a[i]^a[i+1]), end='')

#amateursCTF{saves_space_but_plaintext_in_plain_sight_862efdf9}

 6,You get extra information 1

一个RSA题目,给出提示是p+q+q

from Crypto.Util.number import *
from flag import flag

p = getPrime(512)
q = getPrime(512)
n = p*q
p = p + q
e = 0x10001

extra_information = p + q
ptxt = bytes_to_long(flag)
c = pow(ptxt, e, n)

with open('output.txt', 'w') as f:
    f.write(f"n: {n}\nc: {c}\ne: {e}\nextra_information: {extra_information}")

列方程即可,在有限域上,假设p然后p*(extra-p) == 2*n

#ext = p+q+q 
n =  83790217241770949930785127822292134633736157973099853931383028198485119939022553589863171712515159590920355561620948287649289302675837892832944404211978967792836179441682795846147312001618564075776280810972021418434978269714364099297666710830717154344277019791039237445921454207967552782769647647208575607201
c =  55170985485931992412061493588380213138061989158987480264288581679930785576529127257790549531229734149688212171710561151529495719876972293968746590202214939126736042529012383384602168155329599794302309463019364103314820346709676184132071708770466649702573831970710420398772142142828226424536566463017178086577
e = 65537
gift = 26565552874478429895594150715835574472819014534271940714512961970223616824812349678207505829777946867252164956116701692701674023296773659395833735044077013

P.<x> = PolynomialRing(ZZ)
f = x*(gift-x) - 2*n
f.roots()
'''
[(16257959691785965123734706464775467376081640331002562111989120409985971662652451903577844174825170629728374864253891340059928256201493020465078906423597422,
  1),
 (10307593182692464771859444251060107096737374203269378602523841560237645162159897774629661654952776237523790091862810352641745767095280638930754828620479591,
  1)]
'''
p = 10307593182692464771859444251060107096737374203269378602523841560237645162159897774629661654952776237523790091862810352641745767095280638930754828620479591
q = n//p 
d = inverse_mod(e, (p-1)*(q-1))
m = pow(c,d,n)
bytes.fromhex(hex(int(m))[2:])
#amateursCTF{harder_than_3_operations?!?!!}

7,You get extra information 2

与上题类似,只是这里给出的公式要复杂些

from Crypto.Util.number import *
from flag import flag

p = getPrime(512)
q = getPrime(512)
n = p*q
e = 0x10001
extra_information = (n**2)*(p**3 + 5*(p+1)**2) + 5*n*q + q**2
ptxt = bytes_to_long(flag)
c = pow(ptxt, e, n)

with open('output.txt', 'w') as f:
    f.write(f"n: {n}\nc: {c}\ne: {e}\nextra_information: {extra_information}")

这里给出的数字,显然模n^2后就会很简单(5nq+q^2小于n^2)。

n =95593382112797270045497836514999308524326160650345266525670495575191979116591752182138270308274446464071024826510473429700676303637674960212123982700153540490805215151070356646141514736282385755143090035980011032465519861526291865888128545478530962058792257703950616556136479933021373472378679162332202365371
c =92084942302809419329882275131365664619817865820237979575321652348851871468885232665120732298048355621943772250718055278615366362227084559410831820721620242260588398786014654743749734106956509345330468686120026908164376320923131751798117799981744551407234489862207435686504148347452579942637697333568788391594
e = 65537
gift = 18247071175606431398122118602371784578875472790915317892207044424588309397797319375039984309368393267673885302107217184699052743790470091033147110959310433418937324145720036262540098007724458652548486534453030546582214242131458903058169536052488501597969216020092796160475487905223265691093061136660574497410399108890645909789835984721231354187679269066357591297035974333220513134895660609801438138623213711900681512310067292949714127564635579383633589101296120704659647911638787823818973909534106275908594589830353183557722172234952579827423906720754070119865452363350814918812923981729393142874903734028229195885438296963982680724071663211427931391032589901737528717167662646147224323491202696402122261699504048973334902281462240308032014697804531871922566779026958815207465755155123070196922127199447785648102152027431894178737946151518726929361221425189695069653652163012000609320105988830299015364692678902927254273154427301473090465612473379114039284029813071586214536353994345527805408387636097772645156970939979500155578289301143563369142329343932852167241705090287661795

P.<x> = PolynomialRing(ZZ)
f = 5*n*x + x^2 - gift%(n^2)
f.roots()
'''
[(7591285472030363593819309149475285775894683777302616308552541051471117604695830085885971123084425024738819800112718432254917427153283662301475561286492279,
  1),
 (-477966910563986350227489182574996542621630803251726332628352477875959895582958760910691351541372232320355124132552367148503381518188374801060619913500767710045311547785715377050016723156697704670399227482516363714868650778749064025270728613363777894718986027339553195499114654582534020645555697287222298319134,
  1)]
'''

q = 7591285472030363593819309149475285775894683777302616308552541051471117604695830085885971123084425024738819800112718432254917427153283662301475561286492279
p = n//q 
d = inverse_mod(e, (p-1)*(q-1))
m = pow(c,d,n)
bytes.fromhex(hex(int(m))[2:])
#amateursCTF{omg_it's_my_favorite_epic_thing_where_it_looks_like_a_binomial!!}

8,Weak Primes

危险的素数。

from Crypto.Util.number import *
from flag import flag


def phi(p, q):
    if p == q:
        return (p-1)*p
    else:
        return (p-1)*(q-1)


def getModPrime(modulus):
    p = 2**2047 + getPrime(128)
    p += (modulus - p) % modulus
    p += 1
    iters = 0
    while not isPrime(p):
        p += modulus
    return p


flag = bytes_to_long(flag)
p = getPrime(2048)
q = getModPrime(3)  #2&2047 + x x:128位

n = p*q
e = 65537
d = inverse(e, phi(p, q))
c = pow(flag, e, n)

with open('output.txt', 'w') as f:
    f.write(f"{c} {e} {n}")

这里的 q是1个1然后2000个0,后边是个小数字。显然相当于部分p已知

c = 370166700119554563326700293524870319704004763256654262119894449104706176772874482044402534354559483925810678750583295040186009492862602699249928877036138356553701321228911532381166315117219451599252646161037443638677773448335452169454184649126128208160839615812473681964949474260681309407252497983911530065458322024342070488989834634744554553751033744442777133562880006728695949784378016605501827217487891764858287974975497868476575761808245767776419920653953943909308645219641148059781842549965985460978962674762904340291540963049348315329402682400992061198248164015281139306740473382515823687902194975478278593148943757499949255234839146084048527531039260094417699007944944122181935268581856451893221820787751822253439218792553696260823026812050825184840860779046115894361497044311272212790121893548744564723733339277410520826062844634954480681842402878348394438604008614174962876689774679873193780393514977795415573386873676590322006096014650078099815961622336723988030735004604126330212815079730101246670281603951594454668164446498101094689398208813138108422626474329070881671406846037837730035440159781831683646567880537450109406848708245074512984459160782275457249994037411392698600939900612767527630736567146219710727262081623
e = 65537 
n = 488083532976806084089590477650626358470267060858394130451148014373367242346498608604784613672466909744405459996701984874902955111433679557998635407906878296412067657643904347220463283351362773552751246978077607274145216766545334655548335243712504971716138541137454923418304262722579453503449234943348691033739760475012650728352613028889060355085613061376621942987579754489473480874291539369825016326661019284241520360792002006326580105031556454952959640078682204619119729574400061326916057641853577938962487454572519350659514324945732686868774674946365102130469452130033035796316169837699269465537987386869865246752685777927363998402066435424632408996419501583426553054881545182912748760954659462455734639982442899206639796709805940097444836946542004332363987031978153519279001467795138259248718051692059040739727006813965459458202249823771317542184355133379219308132437177929292011842722331881982132474574412500388535472801822716396916941397653526803129946808695287381941625310393079973085400552213748099067456069854483862307767583161308731242484789357307718063256524501566737965977742241951466168215921734615657708316837781312209557746470448353745855456531626738664181479391533445614906943592551197517774670399668293723760785168301

P.<x> = PolynomialRing(Zmod(n))
f = 2^2047 + x
f.monic().small_roots(X=2^128, beta=0.4)
#[295811685631336287257826408101547213035]
q = int(f(295811685631336287257826408101547213035))
p = n//q 
d = inverse_mod(e, (p-1)*(q-1))
m = pow(c,d,n)
bytes.fromhex(hex(int(m))[2:])

#amateursCTF{wH4t's_4_pR1m3?}

9,OwO time pad

这题想法也很独特。先生成一定长度的随机数据作为key,要求key的长度也明文长度互素。然后用key*len(plain)和plain*len(key)相异或。

import os
import random
from Crypto.Util.strxor import strxor
from math import gcd

with open('secret.txt', 'rb') as f:
    plaintext = f.read()
    keylength = len(plaintext)
    while gcd(keylength, len(plaintext)) > 1:
        keylength = random.randint(10, 100)
    key = os.urandom(keylength)
    key = key * len(plaintext)
    plaintext = plaintext * keylength
    ciphertext = strxor(plaintext, key)
    with open('out.txt', 'w') as g:
        g.write(ciphertext.hex())

先要确定key的长度,由于两个长度互素,所以可以用密文长度分解的来爆破可能的情况。

for v in range(10,100+1):
    if l%v==0 and gcd(v, l//v)<=1:
        print(v)

32
79

由于两个长度互素,那么爆破一下得到32和79,猜是79

但是不管是32还是79都太大了,比赛顶多爆破3+1字节,再回来看这个互素数,由于是对明文加密多次,所以对互素的数来说key的第0位会跟所有plain的位进行异或。所以拿到这些位也就只需要爆破1个字节即可。

另外一个问题是并不知道明文有啥特点,怎么过滤。一般常见的题明文都是可见字符,但试了一下发现都不是可见的。猜测可能是随机值中插了flag ,怎么说flag也得有吧。然后在爆破里过滤flag成功。

msg = open('out.txt').read()
msg = bytes.fromhex(msg)
print(len(msg))

klen = 79
mlen = len(msg)//klen
v = [0]*mlen
for i in range(0, klen*mlen, klen):
    v[i%mlen] = msg[i]

from pwn import xor 
bv = bytes(v)

for i in range(256):
    rr = xor(bv, bytes([i]))
    if b'amat' in rr:
        print(rr)

#amateursCTF{M4yb3_H4v3_b3tt3r_0tP_3ncrYpt10n_n3X7_t1m3_l0L!!_a585b81b}

10,Lottery

对于梅森旋转来说,这是个绕不过去的坎儿。还好有好多库都能实现。这题感觉是用到了极致。

#!/usr/local/bin/python
from Crypto.Util.number import *
from Crypto.Cipher import AES
from math import ceil
import os
import random
from flag import flag

xyz = len(flag)

fullkey = ""
for i in range(128):
    key = ""
    for j in range(128):
        key += str(random.randint(0, 1))
    for j in range(10):
        key = bin(int(key, 2))[:2:-1] + str(random.randint(0, 1))
    key = bin(int(key, 2))[:2:-1]
    key = int(key)   #2进制强转10进制
    key = pow(key, random.randint(0, 256), random.randint(1, 256))
    for i in range(256):
        key = key * i * random.randint(0, 2) + key * random.randint(
            1, 3) + key // (i + 1) * random.randint(2, 4) + key * key
        key = key % 256
        key = key * \
            random.randint(1, random.randint(
                1, random.randint(1, random.randint(1, 1e4))))
    key = bin(key)[2:][::-1]
    fullkey += key[0]
key = long_to_bytes(int(fullkey, 2))

# secure padding
key = b"\x00" * (16 - len(key)) + key
flag = b"\x00" * (16 - len(flag) % 16) + flag

iv = os.urandom(16)
aescbc = AES.new(key, AES.MODE_CBC, iv=iv)
encrypted_flag = aescbc.encrypt(flag).hex()

luck = 0


def draw():
    y = 1
    while random.randint(1, 10000) != 1:
        y += 1
    return y


while True:
    args = input("Enter Arguments: ")
    if args == "flag":
        if luck >= 3:
            print(encrypted_flag)
            break
        else:
            print("Not lucky enough.")
    elif args == "":
        print("Bruh please input something plz!!")
        break
    elif args == "draw":
        if random.randint(1, 10000) == 1:
            luck += 1
            if luck == 1:
                print("Success! 2 more draws until you can see the flag!")
            elif luck == 2:
                print("Success! 1 more draw until you can see the flag!")
            elif luck == 3:
                print("Success! Now go get that flag!")
                for i in range(random.randint(1, 8)):
                    print(random.randint(0, 1), end="")
                print()
            else:
                print("Your lucky number is:", bytes_to_long(
                    os.urandom(getRandomInteger(3))))
        else:
            print("Better luck next time!")
            break
    elif args[:3] == "win":
        if args[3:] == "":
            print("if you were to draw, you would've drawn", draw(), "times")
            break
        else:
            # good luck!
            if bytes_to_long(os.urandom(getRandomInteger(10))) == 69420**3:
                try:
                    print("good job. you won.")
                    print(eval(args[3:]))
                except:
                    print(
                        args[3:], "gave an error, too bad so sad. Try again next century. Maybe try printing the flag next time. ;) Just saying.")
            else:
                print("Didn't win hard enough, sorry.")
    elif args == "rsa":
        print(pow(bytes_to_long(flag), 3, getPrime(128)*getPrime(128)))
        print(pow(xyz, 3, getPrime(128)*getPrime(128)))
    # random way of getting you to minimize query count.
    elif ord(args[0]) % (getRandomInteger(7) + 1) == 3:
        print("Too many RNG calls!")
    else:
        try:
            assert str(int(args)) == args, "get better"
            if 0 < int(args) <= 128:
                print(random.randrange(1, 2**int(args)))
            elif int(args) > 128:
                print(random.randrange(1, len(str(args))))
            else:
                print("Invalid input")
        except:
            try:
                # limit loop length because it would be bad if it were uncapped.
                args = int(args[1:]) % 10**5
                for i in range(args):
                    random.randrange(1, 2)
            except:
                print("Invalid input.")
print("Exiting...")

先是用了N多人rand生成key,这个数量是

128*(128+10+2+256*(3+4))

然后有几个功能菜单,

  1. flag 是拿到flag的密文,但前提是draw成功3次
  2. draw 当这一次恰好randint(1,10000) == 1就成功1次
  3. win 他自己执行1次draw(当rand == 1结束)后边是参数用的os.random没问题,成功不了用不到。
  4. rsa 这个也没用,getPrime使用的随机数不能复现,而且e=0x10001太大
  5. ord(args[0]) % (getRandomInteger(7) + 1) == 3 这个没用,但写程序时遇到需要跳一下
  6. 0 < int(args) <= 128 会返回一个指定长度的随机数
  7. str(int(args)) == args 首位不是数字时,会执行指定次数randint()

这题思路不复杂,只是中间有点卡。

先通过6取得一定数量的随机数来复原random的state,实现程序与远端同步。

然后用计算出下一次randint(1,10000)==1时需要的randint(1,2)的次数到7跑然后到2去draw一次,3次后拿到密文。然后再用这个随机数向前推到key解密。

这量有一个问题randint(1,10000)和randint(1,2)次数并不相同。这涉及到随机数生成的算法。

MT19937每次生成1个32位随机数。当randint生成时先转成randblewg再先计算所需要的最少位数,然后取随机数,比如10000会取9999,这时从生成的随机数最取14位,但这个数可能会比9999大,当大于9999时这个随机数会被作废,然后重新取。

这样计算的randint(1,2)次数可能下一次就过了randint(1,10000)==1 这时候跳过这个draw。直到能够恰好下一次randint==1去执行1次draw。

另外randint(1,2)的次数也只能猜,经过测试这个次数大约是1000的3/4次,所以可以每次通过这个数来重算需要的近似值。直到小于4再1次次试(rand每次都需要尝试复制对象,处理起来很费时间)

from pwn import *
from extend_mt19937_predictor import ExtendMT19937Predictor
import random 
import copy 

#random.seed(0)
def get_128():
    p.sendlineafter(b"Enter Arguments: ", b'128')
    v = p.recvline()
    if b"Too many RNG calls!" in v:
        return -1
    n = int(v)
    return n 

def get_times(t, p2):    
    for i in range(t):
        p2.predict_randrange(1,2)
    
    y = 1
    while p2.predict_randint(1, 10000) != 1:
        y += 1
    return y

   
p = remote('amt.rs', 31311)
#p = process(['python', 'main.py'])
context.log_level = 'debug'

#导入156个128位值,恢复random
data = []
while len(data)<156:
    v = get_128()
    if v != -1:
        data.append(v-1)  #rand返回值从1开始,转为0开始

print(data)

predictor = ExtendMT19937Predictor()
for i in range(156):
    predictor.setrandbits(data[i], 128) 

def get_draw():
    #找出
    t3 = 0 #已投计数
    while True:
        pa = copy.deepcopy(predictor)
        t1 = get_times(0, predictor)
        t2 = t1 - t1//4 - 50
        print(t1,t2)
        ti = t2
        ok = False
        while ti<=t1:
            if ti%20 == 0:
                print(ti)
            pb = copy.deepcopy(pa)
            v = get_times(ti, pb)
            if v == 1:
                print('Got:',ti,'+',t3, v)
                ok = True
                break

            if v<=4:
                print('neer:',ti,v)
                ti += 1
            else:
                ti += v//4*3

        if not ok:
            t3 += t1
        else:
            break
        
    p.sendlineafter(b"Enter Arguments: ", b'A'+ str(ti + t3).encode())
    p.sendlineafter(b"Enter Arguments: ", b"draw")

get_draw()
get_draw()
get_draw()

p.sendlineafter(b"Enter Arguments: ", b'flag')
print(p.recvline())

拿到密文,就算完成了一半

然后从上面得到的state恢复随机数,向前取 128*(128+10+2+256*7),由于rand所用32位整型要多,所以从这里开始,每次向前取一个值然后爆破。

这里爆破得到key但由于没有iv得到的flag是不全的,好在他给出的前pad,而flag长度是113这样在pad以后第1组数据只有flag的首字母a,所以可以用密文第1组作为 iv对后边的密文解密,得到结果前面加a即可。

本以为这个会爆破很久,可没想到一秒就成功了。

from extend_mt19937_predictor import ExtendMT19937Predictor
import random 
import copy 
from Crypto.Util.number import long_to_bytes,bytes_to_long 
from Crypto.Cipher import AES

data = [123271252609156750538259515693709084592, 247399300171605801816441913934459830541, 289014761715331321629662878549177000106, 13260238211780539999187552578480586383, 118411364354061078566646547712857861375, 330814572699759184863253703829746332394, 231743926216357474984644561419462500916, 79377783622613425523204365873640520303, 148825718147381089006166915562612033483, 43963317446948935740611754412661291290, 80014578563238346841846767165896494867, 90899822548646858427219617456228765591, 157463328762064997782092720008430696564, 103108095985884641739877166211018472235, 42405723326844751589655230645902410864, 62583683405974793112313496192083591225, 221712001093723076796777547415906537175, 91174205548316554356444641015417868907, 293254991696652099639427630793634127810, 277730625433133351719600726207539749570, 245121756569512407510110497850502809550, 268580352884277648338427157211623694529, 100527840571378367289460958048899395010, 72837296261708434550133595205940330758, 224455277018582244747255690219362861766, 332934227569053175902709174209922418170, 32512678102192574000409204862253165181, 295018550745472889328344382745902160749, 285594979887133321686802329387381506250, 39635489998643908291073138339333480028, 246517430190274100499961804456641264958, 39098311226891167036692086619056779767, 164349156761990388377451993165248773431, 309843453776748607697259081493806346519, 307772721036435331697628746056720155439, 117132060334425218643034459307077049990, 51013624404957510796568651940697039729, 286574209433169743908088344357462777940, 52403376118044347539693355564178446084, 95642938597842008234603822229145385331, 121892990023707495374457353500304194686, 319474510485690286459277426719776427608, 59767451040898243966344164116707599842, 277141286589682307155549698023014778134, 284658172155259640139203113216323537065, 254613485062418912650634967720455416437, 26938443121968774529821850424851584418, 34047423079827511759000761557301180954, 279634173171447892715278383308283577251, 111157631054894869779285765052711250118, 224172603246495732448556168181553597945, 305221695150374344959436920922821417796, 38482880002810250536163138153640894277, 339193159373721441775815382868776122102, 47628118659023468834610862818989354222, 301968478454044450336723193452691407240, 264640583510768059048427272018618235283, 318568855228912737407830085449347675330, 159764803785927016879835657921256878047, 168043094675667542877555217442264273838, 232242360065036777161001637654474122687, 282013144666189461927220533789097918481, 335715157736512202872635368127787996512, 47420664387727533858903515655209503719, 123321968791334685378477286541634345916, 27035060026400111889178814843965797711, 290673719513709919887798260077553539124, 23801772061398037613446528607981744232, 304671193055680014308831392972032000031, 21724204079987550947738092924401227831, 174969007458497459167163806764741833810, 158246501337399312770076062464121694923, 184715693024991028488776996436560434197, 61160217582672512441077364286535908457, 120724499212137395781814588994183820253, 230662380648751754659925625371439159365, 180879469843362172268027489111856238085, 138290503898084258261290862801790548669, 158486749549664511619055434708316321830, 243018165913656116628535646761494651705, 46195644101540372839601022545388300021, 156741488647334071756075736219841008421, 118248156824691031166535121414396853633, 284210818586003544593448146321659344120, 84244964574712065959799009654533437043, 19111810091663490210746800183541501953, 54202534921955336181193575607266412252, 200676803814515215031863846164865092109, 214615094833453941931218530690030310250, 86017703683975087481917963320092430384, 171076805218217949828024106045134144174, 65141663114994558054125182595384068743, 262932455867372971080019909727468134656, 56683538889739533544426787325452342036, 106615090472038106945904067429013136040, 92043729158730710806413958556281775553, 300114340848533419159474988144814448360, 285935664005570515304600367235401077870, 12817993961175711971377838500653868101, 189584797362148876095392175535657094626, 268252392631378269115097132570370304556, 266617510888171332449111002917526589267, 12718824644818582441102575175261685292, 266881252351043386379136502061668977347, 156006162604429105265040144514157440802, 308244169745287372260282766101382874098, 34227036943540756336825356288935470132, 263572746426727429303395762738766305353, 220239335717085654028055130688015733169, 233345798692213355449489992126843375729, 244161079633486514647976414924473522806, 272023628853330719313961220000943785982, 219845620578067699767499378609657837204, 275753957489338831445849773652487403577, 134772123364008688449736834016480086941, 287819064687599326831890774244927834352, 192356098890686068061518324173921602758, 290507034385884046563212230166562540635, 82574822871957613809451782598182635479, 139730639867175942923467718904091319763, 87936111771294330756611357684572227847, 63000811598982433021915020180163340252, 45508098617593413436657026341419808660, 286209275850597419611062652829206118259, 75917330499190375527901974943741429079, 69331189092142570953871106896505972003, 217465410374726979043233069534009396907, 240416991483108225917835952719741458120, 100577207598900758627567591831629013751, 102882917697337321486555405564968190244, 61443624282339548901762716327849161593, 263726297123880074379497187750342832662, 205478023038383994490676776900314120124, 198957037745994275253541519230448054908, 237346732980264673319937422024836257937, 265943803434220947524422859135076915210, 25573823634204318695661184154725789289, 12228933312401731210197039970218337808, 241197047154901089946866712935934032199, 15429393453623112954406826139287386094, 145802634702841395234230450335905694412, 157766638651800847028386808114738325714, 208687012566152946783075050925152837158, 53458505911618637059470908306195814731, 176955768794324332948897618660827671589, 252732686589127613133879876035977804267, 251474606395181828318604777079665517837, 294954280449016142229330263018545339551, 112540470944135435835923827336892166778, 330053564165842416854993497524615565928, 101155032469455856121714955850100003887, 303084174197712378718864825228956681339, 40577757380857680896227492840096540736, 74891836476087557562512633270397121809, 16628508646164655581338286683608004263, 214795729792242569249513628686609281324]

c = bytes.fromhex('8126089e78433127652e7f7552021fbbc2ba487440f7adab257166dbc66d7d1275bb3b401313c76c5ac7741f0153d28959de15d0d9099d84f9fdbfba4229532331d8da26477aaf88d97017de81c21b62d2fd876dc7bc996bcd06aeec9c05898d9abc78bac30882e903feee880221542610bbf2d278173992085f9040174fd03f')


def decrypt(pp):
    fullkey = ""
    for i in range(128):
        key = ""
        for j in range(128):
            key += str(pp.predict_randint(0, 1))
        for j in range(10):
            key = bin(int(key, 2))[:2:-1] + str(pp.predict_randint(0, 1))
        key = bin(int(key, 2))[:2:-1]
        key = int(key)   #2进制强转10进制
        key = pow(key, pp.predict_randint(0, 256), pp.predict_randint(1, 256))
        for i in range(256):
            key = key * i * pp.predict_randint(0, 2) + key * pp.predict_randint(
                1, 3) + key // (i + 1) * pp.predict_randint(2, 4) + key * key
            key = key % 256
            key = key * \
                pp.predict_randint(1, pp.predict_randint(
                    1, pp.predict_randint(1, pp.predict_randint(1, 1e4))))
        key = bin(key)[2:][::-1]
        fullkey += key[0]
    key = long_to_bytes(int(fullkey, 2))
    
    # secure padding
    key = b"\x00" * (16 - len(key)) + key
    
    iv = c[:16]
    aescbc = AES.new(key, AES.MODE_CBC, iv=iv)
    flag = aescbc.decrypt(c[16:])
    if all( v<0x7f for v in flag):
        print(flag)
        return 1
    return 0
    
pr = ExtendMT19937Predictor()
for i in range(156):
    pr.setrandbits(data[i], 128) 

length = 128*(128+10+2+256*7)
#length += length//4

for i in range(0, length, 16):
    pr.backtrack_getrandbits(512)

i = 0
while True:
    i+=1
    pr.backtrack_getrandbits(32)
    pt = copy.deepcopy(pr)
    if decrypt(pt)==1:
        break 
    if i%100 == 0:
        print(i)

#b'mateursCTF{th3r3"s_4_r3As0n-wHy_n0_0n3-fr<>n7.pads^th3!r_fIa6s-l0l,wH0-gu3s5ed!!!;4ls0,1g~r4n&om_n0t_so_rand<>m}'
#amateursCTF{th3r3"s_4_r3As0n-wHy_n0_0n3-fr<>n7.pads^th3!r_fIa6s-l0l,wH0-gu3s5ed!!!;4ls0,1g~r4n&om_n0t_so_rand<>m}

PWN

前几个pwn都是关于mmap的,mmap可写可执行的话还是很方便的,但第1题是个论文题,要计算mmap可能会配置到的地址没看明白,另外3个都很简单,略。

REV

volcano

这里有几个判断,先是判断余数是多少,这个用中国剩余定理可以轻松解出

_BOOL8 __fastcall sub_12BB(unsigned __int64 a1)
{
  if ( (a1 & 1) != 0 )
    return 0LL;
  if ( a1 % 3 != 2 )
    return 0LL;
  if ( a1 % 5 != 1 )
    return 0LL;
  if ( a1 % 7 == 3 )
    return a1 % 0x6D == 55;
  return 0LL;
}

然后是判断转2进制后1的个数,10进制各位数字和相同,和两个pow相同

只需要算出两个数字,转入即可

import itertools

v7 = 18476 #crt([0,2,1,3,55],[2,3,5,7,0x6d])

mod = 22890
v7 = mod*1000000 + v7

i=0
for v8s in itertools.permutations(str(v7)):
    v8 = int(''.join(v8s))
    if v7%2 == v8%2:
        bv8 = bin(v8)[2:].replace('0','')
        if 0x10<len(bv8)<=0x1a:
            print(v8)
            i+=1
            if i>10:
                break


v10 = 4919

v7,v8 = 22890018476, 22890018746
v9 = 3 

'''
┌──(kali㉿kali)-[~/ctf/0715]
└─$ nc amt.rs 31010
Give me a bear: 2289018476
Give me a volcano: 2289018746
Prove to me they are the same: 3
That looks right to me!
amateursCTF{yep_th0se_l00k_th3_s4me_to_m3!_:clueless:}
'''

headache

这个确实头疼,

主程序直接调用check

__int64 __fastcall main(int a1, char **a2, char **a3)
{
  char s[264]; // [rsp+10h] [rbp-110h] BYREF
  unsigned __int64 v5; // [rsp+118h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  printf("Enter flag: ");
  __isoc99_scanf("%s", s);
  if ( strlen(s) == 61 )
  {
    if ( (unsigned int)check_flag(s) )
      puts("Correct!");
    else
      puts("Wrong!");
    return 0LL;
  }
  else
  {
    puts("Wrong!");
    return 0LL;
  }
}

check_flag就麻烦了,先作个检查,然后去解密下一个检查

__int64 __fastcall check_flag(_BYTE *a1)
{
  _DWORD *v2; // rsi

  if ( (*a1 ^ a1[25]) != 86 )
    return 0LL;
  v2 = &loc_4012A4;
  do
    *v2++ ^= 0xEA228DE6;
  while ( *(v2 - 1) != 0xEA228DE6 );
  return ((__int64 (*)(void))loc_4012A4)();
}

所以这就需要写个程序一步步去patch程序,flag很长,如果十个八个就手工了。

from pwn import xor,p32,u32

data = open('headache', 'rb').read()

ft = 0x4374
rd = b''
while True:
    vv = data[ft+1:ft+1+4]
    st = u32(data[ft+9:ft+9+4]) - 0x400000 
    print(hex(u32(vv)), hex(st))
    
    rd = data[:st]
    k = 0
    while True:
        rd += xor(data[st+k: st+k+4],vv)
        k+=4
        if rd[-4:] == vv:
            break 
    rd += data[st+k:]
    data = rd 
    
    ft -= 36
    if ft<st:
        break

open('head3','wb').write(data)

每一步都取出解密异或用的密钥,然后对原程序修改。输出起点,后边用。

然后从程序最取出计算校验用的算式

v = [[0,0x1290],[0xea228de6,0x12a4],[0xbebf59e8,0x12bc],[0xcb9d2ad7,0x12d4],[0xac9e22ce,0x12ec],[0xe8dc6f5f,0x1304],[0xa4602f85,0x131c],[0x17d008d1,0x1334],[0x2251b924,0x134c],[0x8fb99d4f,0x1364],[0x1ae715ea,0x137c],[0x720e548f,0x1394],[0xad5e3e25,0x13ac],[0xc80c4dc7,0x13c4],[0x5de42562,0x13dc],[0x337bffcc,0x13f4],[0xe9d6471,0x140c],[0xaab604fe,0x1424],[0x31ad7613,0x143c],[0xf09460bd,0x1454],[0xd94cd408,0x146c],[0x98562060,0x1484],[0x89209f48,0x149c],[0x9be9b2eb,0x14b4],[0x86bf7a35,0x14cc],[0x2511008d,0x14e4],[0xda902ec1,0x14fc],[0xe230cb28,0x1514],[0xbdbd4686,0x152c],[0x372a2158,0x1544],[0xf231acd0,0x155c],[0x9e81156c,0x1574],[0x9f2e55e9,0x158c],[0x60c39d71,0x15a4],[0x9a2eb090,0x15bc],[0xe57e2785,0x15d4],[0x14c72fdc,0x15ec],[0xc4739481,0x1604],[0x55a822d4,0x161c],[0x5a15e633,0x1634],[0x1470814e,0x164c],[0x9d4140f1,0x1664],[0x8a2eb5c1,0x167c],[0x4864cb4e,0x1694],[0x89de67d7,0x16ac],[0xfe6e56e6,0x16c4],[0x4e721b78,0x16dc],[0xa7bbec05,0x16f4],[0x237312d4,0x170c],[0xbb811bf5,0x1724],[0x792c1792,0x173c],[0x18f3a7a6,0x1754],[0x90835a18,0x176c],[0x8d7851b2,0x1784],[0xa2068719,0x179c],[0x6fd2a57f,0x17b4],[0x4284baaa,0x17cc],[0xfe852bc9,0x17e4],[0x764f7fe0,0x17fc],[0x31bf0107,0x1814],[0xa4d68dea,0x182c],[0xf11fc76a,0x1844],[0xe9c81579,0x185c],[0x9e6067b1,0x1874],[0x416f6df3,0x188c],[0xd59c7429,0x18a4],[0xedad9671,0x18bc],[0x6636da8f,0x18d4],[0xbbc76f9a,0x18ec],[0x86669c2b,0x1904],[0xa0f56cd6,0x191c],[0x8eb09715,0x1934],[0x390afda6,0x194c],[0x21c40230,0x1964],[0xd002cb,0x197c],[0xc01e6302,0x1994],[0x6c05bded,0x19ac],[0x43c2ee7c,0x19c4],[0x4ac7b5d2,0x19dc],[0x88615eb9,0x19f4],[0xe4d5a069,0x1a0c],[0xb7318dc9,0x1a24],[0x2955243,0x1a3c],[0x8baa1ce6,0x1a54],[0x432a3638,0x1a6c],[0xb1b0df21,0x1a84],[0x3f13efa1,0x1a9c],[0x762f8e7c,0x1ab4],[0x3bf9064,0x1acc],[0xbfdf4406,0x1ae4],[0x21cfe018,0x1afc],[0x7a0e8255,0x1b14],[0x3040dc0b,0x1b2c],[0x9ee8758f,0x1b44],[0x2157de89,0x1b5c],[0x3e530593,0x1b74],[0xf574a9f3,0x1b8c],[0x1472b601,0x1ba4],[0x3d088b57,0x1bbc],[0x1da14b43,0x1bd4],[0xfb224279,0x1bec],[0x7984cc26,0x1c04],[0xaaae835b,0x1c1c],[0x45583943,0x1c34],[0xaca13362,0x1c4c],[0xb6b06ca5,0x1c64],[0x2a10e8ca,0x1c7c],[0xad882578,0x1c94],[0x1b41e035,0x1cac],[0xc6126ea4,0x1cc4],[0x53e6014,0x1cdc],[0x30c02c53,0x1cf4],[0x46706531,0x1d0c],[0x6f7ee28e,0x1d24],[0x3a552133,0x1d3c],[0xa416729a,0x1d54],[0xe10d6cc1,0x1d6c],[0x7640729e,0x1d84],[0xcf35d440,0x1d9c],[0xa5b949cf,0x1db4],[0x26ff665b,0x1dcc],[0xf0be5c29,0x1de4],[0x1fb524c0,0x1dfc],[0x98ba54ae,0x1e14],[0xa2dfbf47,0x1e2c],[0xa11e2b96,0x1e44],[0x47b2b3a7,0x1e5c],[0xa4694342,0x1e74],[0xf42921f2,0x1e8c],[0xa790a8f1,0x1ea4],[0xdf4659c3,0x1ebc],[0x65c39387,0x1ed4],[0x33cd4a64,0x1eec],[0xcbff4143,0x1f04],[0x2559a70b,0x1f1c],[0x572d7afb,0x1f34],[0x1693a840,0x1f4c],[0xa88eadb,0x1f64],[0xba66c7de,0x1f7c],[0x41ee2c67,0x1f94],[0x9d5b903d,0x1fac],[0x83e5e76b,0x1fc4],[0xde42b086,0x1fdc],[0x15f81ad2,0x1ff4],[0x52aac40e,0x200c],[0xaeed95e6,0x2024],[0x61709331,0x203c],[0xdbfa3914,0x2054],[0xf46dba84,0x206c],[0x7f1ee015,0x2084],[0xfcea10c7,0x209c],[0x1bba6f85,0x20b4],[0x57ab48a1,0x20cc],[0xe05e7aab,0x20e4],[0xbf65b2e2,0x20fc],[0x31e49cca,0x2114],[0xd0d47cf1,0x212c],[0xfbb22798,0x2144],[0xb0442b30,0x215c],[0xfe5e7d01,0x2174],[0xd61669bb,0x218c],[0xf041ead1,0x21a4],[0xaed5a91e,0x21bc],[0xb0d41862,0x21d4],[0x7b3c01b7,0x21ec],[0xc78283c7,0x2204],[0xafbd1990,0x221c],[0x8132232,0x2234],[0xdad8064b,0x224c],[0xd9032473,0x2264],[0xd07c2fdc,0x227c],[0xdf8ba959,0x2294],[0xc62ec786,0x22ac],[0x76e18e7d,0x22c4],[0x379f3842,0x22dc],[0x4321778b,0x22f4],[0xa170a6e7,0x230c],[0x177abfa2,0x2324],[0x6e6b5aa5,0x233c],[0xdebfb6dc,0x2354],[0xd58477d,0x236c],[0x72801d20,0x2384],[0xd2f18dd3,0x239c],[0x11d01023,0x23b4],[0x3b5c6514,0x23cc],[0x796e9e8e,0x23e4],[0x23f0658a,0x23fc],[0x54604203,0x2414],[0xe3766b6f,0x242c],[0xb22bcfe1,0x2444],[0x9ffc9966,0x245c],[0x1e9ee30c,0x2474],[0xc859c30,0x248c],[0x6167bc3b,0x24a4],[0xccc69fff,0x24bc],[0xb1926e94,0x24d4],[0x32dd610a,0x24ec],[0xb5c5ea10,0x2504],[0x7a25ffcb,0x251c],[0xc0b79a59,0x2534],[0x28e28616,0x254c],[0xdbdaf583,0x2564],[0x14d92591,0x257c],[0xdd3358ba,0x2594],[0xd0c2a9c0,0x25ac],[0xd9d55c0,0x25c4],[0xf2248f09,0x25dc],[0xa3f9e371,0x25f4],[0xebd28a10,0x2608],[0x95f5ce16,0x261c]]

from pwn import xor,p32,u32

data = open('head3', 'rb').read()

for _,pos in v:
    if data[pos+2] == 0x7f:
        k1 = data[pos+3]
        kp = 4
    elif data[pos+2] == 0x3f:
        k1 = 0
        kp = 3
    else:
        print('err1', hex(pos), data[pos:pos+12])

    if data[pos+kp+2] == 0x7f:
        k2 = data[pos+kp+3]
        kp+=4
    elif data[pos+kp+2] == 0x3f:
        k2 = 0
        kp+=3
    else:
        print('err2', hex(pos), data[pos:pos+12])

    k3 = data[pos+kp+3]
    print(f"s.add(d[{k1}]^d[{k2}] == {k3})")
        
'''
.text:0000000000401290 44 8A 7F 19                   mov     r15b, [rdi+19h]
.text:0000000000401294 44 32 3F                      xor     r15b, [rdi]
.text:0000000000401297 41 80 FF 56                   cmp     r15b, 56h ; 'V'
'''        
        

最后运算这个z3式子

from z3 import *

d = [BitVec(f'd_{i}',8) for i in range(61)]

s = Solver()

head = b'amateursCTF{'
for i,v in enumerate(head):
    s.add(d[i] == v)

s.add(d[60] == ord('}'))

for i in range(len(head), 60):
    s.add(Or(And(ord('0')<=d[i], d[i]<=ord('9')),And(ord('A')<=d[i], d[i]<=ord('Z')),And(ord('a')<=d[i],d[i]<=ord('z')), d[i]==ord('_') ) )

s.add(d[25]^d[0] == 86)
s.add(d[45]^d[14] == 29)
s.add(d[34]^d[33] == 5)
s.add(d[52]^d[40] == 5)
s.add(d[56]^d[12] == 5)
s.add(d[11]^d[4] == 30)
s.add(d[55]^d[19] == 18)
s.add(d[43]^d[60] == 78)
s.add(d[22]^d[17] == 67)
s.add(d[59]^d[8] == 51)
s.add(d[52]^d[46] == 5)
s.add(d[43]^d[31] == 91)
s.add(d[29]^d[14] == 15)
s.add(d[45]^d[37] == 29)
s.add(d[54]^d[1] == 50)
s.add(d[29]^d[54] == 56)
s.add(d[23]^d[10] == 42)
s.add(d[17]^d[8] == 112)
s.add(d[33]^d[30] == 62)
s.add(d[58]^d[29] == 84)
s.add(d[6]^d[56] == 30)
s.add(d[5]^d[4] == 16)
s.add(d[15]^d[16] == 66)
s.add(d[4]^d[30] == 58)
s.add(d[29]^d[33] == 6)
s.add(d[28]^d[37] == 6)
s.add(d[40]^d[29] == 86)
s.add(d[11]^d[5] == 14)
s.add(d[42]^d[18] == 45)
s.add(d[43]^d[18] == 108)
s.add(d[48]^d[35] == 4)
s.add(d[49]^d[37] == 55)
s.add(d[34]^d[36] == 7)
s.add(d[9]^d[42] == 38)
s.add(d[52]^d[47] == 70)
s.add(d[34]^d[29] == 3)
s.add(d[5]^d[40] == 68)
s.add(d[59]^d[39] == 47)
s.add(d[38]^d[53] == 23)
s.add(d[30]^d[31] == 55)
s.add(d[7]^d[9] == 39)
s.add(d[53]^d[22] == 2)
s.add(d[59]^d[55] == 3)
s.add(d[10]^d[48] == 35)
s.add(d[10]^d[24] == 47)
s.add(d[56]^d[44] == 29)
s.add(d[39]^d[18] == 0)
s.add(d[20]^d[15] == 107)
s.add(d[39]^d[41] == 0)
s.add(d[36]^d[53] == 17)
s.add(d[26]^d[1] == 90)
s.add(d[39]^d[14] == 55)
s.add(d[48]^d[9] == 49)
s.add(d[43]^d[53] == 65)
s.add(d[6]^d[12] == 27)
s.add(d[33]^d[3] == 21)
s.add(d[8]^d[24] == 42)
s.add(d[52]^d[2] == 85)
s.add(d[15]^d[27] == 93)
s.add(d[7]^d[59] == 3)
s.add(d[38]^d[23] == 9)
s.add(d[29]^d[8] == 36)
s.add(d[12]^d[5] == 28)
s.add(d[55]^d[29] == 20)
s.add(d[37]^d[2] == 9)
s.add(d[55]^d[41] == 44)
s.add(d[19]^d[33] == 0)
s.add(d[51]^d[3] == 68)
s.add(d[57]^d[50] == 94)
s.add(d[39]^d[33] == 62)
s.add(d[4]^d[25] == 82)
s.add(d[14]^d[7] == 27)
s.add(d[36]^d[3] == 23)
s.add(d[48]^d[17] == 86)
s.add(d[24]^d[42] == 27)
s.add(d[56]^d[24] == 5)
s.add(d[24]^d[52] == 93)
s.add(d[3]^d[40] == 69)
s.add(d[26]^d[9] == 99)
s.add(d[13]^d[34] == 59)
s.add(d[30]^d[35] == 62)
s.add(d[30]^d[53] == 45)
s.add(d[6]^d[2] == 19)
s.add(d[42]^d[24] == 27)
s.add(d[50]^d[29] == 10)
s.add(d[29]^d[41] == 56)
s.add(d[36]^d[1] == 14)
s.add(d[1]^d[33] == 12)
s.add(d[12]^d[46] == 88)
s.add(d[54]^d[25] == 104)
s.add(d[53]^d[22] == 2)
s.add(d[48]^d[36] == 6)
s.add(d[17]^d[45] == 70)
s.add(d[1]^d[5] == 24)
s.add(d[12]^d[24] == 0)
s.add(d[52]^d[16] == 66)
s.add(d[58]^d[11] == 72)
s.add(d[33]^d[18] == 62)
s.add(d[52]^d[22] == 68)
s.add(d[42]^d[26] == 69)
s.add(d[30]^d[19] == 62)
s.add(d[12]^d[45] == 28)
s.add(d[25]^d[57] == 4)
s.add(d[32]^d[8] == 38)
s.add(d[11]^d[38] == 30)
s.add(d[35]^d[41] == 62)
s.add(d[56]^d[15] == 88)
s.add(d[57]^d[23] == 95)
s.add(d[34]^d[43] == 87)
s.add(d[57]^d[21] == 64)
s.add(d[1]^d[16] == 27)
s.add(d[17]^d[6] == 65)
s.add(d[2]^d[31] == 9)
s.add(d[44]^d[19] == 16)
s.add(d[44]^d[43] == 66)
s.add(d[55]^d[52] == 71)
s.add(d[10]^d[35] == 39)
s.add(d[34]^d[1] == 9)
s.add(d[36]^d[33] == 2)
s.add(d[50]^d[33] == 12)
s.add(d[37]^d[31] == 0)
s.add(d[54]^d[27] == 54)
s.add(d[51]^d[58] == 3)
s.add(d[44]^d[25] == 70)
s.add(d[13]^d[11] == 36)
s.add(d[27]^d[4] == 12)
s.add(d[9]^d[36] == 55)
s.add(d[35]^d[1] == 12)
s.add(d[21]^d[57] == 64)
s.add(d[26]^d[23] == 91)
s.add(d[31]^d[53] == 26)
s.add(d[42]^d[27] == 27)
s.add(d[44]^d[20] == 46)
s.add(d[33]^d[51] == 81)
s.add(d[17]^d[55] == 64)
s.add(d[22]^d[35] == 17)
s.add(d[12]^d[25] == 94)
s.add(d[9]^d[2] == 53)
s.add(d[13]^d[50] == 50)
s.add(d[58]^d[27] == 90)
s.add(d[3]^d[45] == 1)
s.add(d[37]^d[30] == 55)
s.add(d[53]^d[56] == 30)
s.add(d[8]^d[12] == 42)
s.add(d[20]^d[22] == 47)
s.add(d[4]^d[30] == 58)
s.add(d[24]^d[47] == 27)
s.add(d[34]^d[27] == 13)
s.add(d[28]^d[27] == 7)
s.add(d[48]^d[56] == 9)
s.add(d[20]^d[16] == 41)
s.add(d[52]^d[8] == 119)
s.add(d[50]^d[15] == 89)
s.add(d[24]^d[23] == 5)
s.add(d[45]^d[11] == 14)
s.add(d[58]^d[2] == 82)
s.add(d[14]^d[58] == 91)
s.add(d[54]^d[9] == 11)
s.add(d[47]^d[8] == 49)
s.add(d[3]^d[41] == 43)
s.add(d[3]^d[60] == 9)
s.add(d[24]^d[43] == 90)
s.add(d[8]^d[18] == 28)
s.add(d[30]^d[8] == 28)
s.add(d[22]^d[25] == 71)
s.add(d[52]^d[5] == 65)
s.add(d[20]^d[1] == 50)
s.add(d[14]^d[51] == 88)
s.add(d[18]^d[45] == 42)
s.add(d[7]^d[29] == 20)
s.add(d[23]^d[42] == 30)
s.add(d[28]^d[29] == 9)
s.add(d[49]^d[36] == 60)
s.add(d[10]^d[39] == 25)
s.add(d[57]^d[10] == 117)
s.add(d[13]^d[55] == 44)
s.add(d[57]^d[25] == 4)
s.add(d[41]^d[25] == 104)
s.add(d[59]^d[20] == 47)
s.add(d[23]^d[14] == 4)
s.add(d[26]^d[27] == 94)
s.add(d[58]^d[5] == 70)
s.add(d[16]^d[37] == 30)
s.add(d[57]^d[14] == 91)
s.add(d[25]^d[17] == 4)
s.add(d[6]^d[40] == 67)
s.add(d[40]^d[13] == 110)
s.add(d[54]^d[30] == 0)
s.add(d[25]^d[13] == 104)
s.add(d[2]^d[18] == 62)
s.add(d[13]^d[10] == 25)
s.add(d[39]^d[33] == 62)
s.add(d[18]^d[34] == 59)
s.add(d[6]^d[35] == 19)
s.add(d[49]^d[38] == 58)
s.add(d[4]^d[2] == 4)
s.add(d[48]^d[52] == 81)
s.add(d[58]^d[14] == 91)
s.add(d[45]^d[6] == 7)
s.add(d[19]^d[8] == 34)
s.add(d[4]^d[54] == 58)
s.add(d[34]^d[3] == 16)
s.add(d[12]^d[11] == 18)
s.add(d[37]^d[60] == 21)
s.add(d[57]^d[43] == 0)
s.add(d[13]^d[7] == 44)
s.add(d[24]^d[7] == 26)
s.add(d[55]^d[53] == 1)
s.add(d[25]^d[6] == 69)
s.add(d[0x27]^d[0x1f] == 0x37)  #手工处理

if s.check() == sat:
    v = s.model()
    print(''.join([chr(v[d[i]].as_long()) for i in range(61)]))
else:
    print('x')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值