一些知识
- $_GET['a']此类传参, _GET['a']变量(或者a变量)的值为传入值,是一个数,也可传递数组,如a[0]=1&a[1]=2
- $_GET此类传参, _GET变量的值为一个数组,如a=1&b=2,则传入Array ( [a] => 1 [b] => 2 )
- $_POST['a']此类传参, _POST['a']变量(或者a变量)的值为传入值,是一个数,也可传递数组,如a[0]=1&a[1]=2
- $_POST此类传参, _POST变量的值为一个数组,如a=1&b=2,则传入Array ( [a] => 1 [b] => 2 )
- 数组不能直接用echo打印,要用print_r($_POST);但print_r不能打印变量
1
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if(preg_match("/[0-9]/", $num)){
die("no no no!");
}
if(intval($num)){
echo $flag;
}
}
- pregmatch()函数无法处理数组
- 关于正则匹配:此函数只有1和0两个返回值,如果要查询总匹配次数要pregmatchall()函数,"/xxx/"为模式分隔符,无含义,/XXX/i表示忽略大小写,\bXXX\b表示完全匹配,比如cat和cate不匹配
- 传参?num[20]=a
2
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==="4476"){
die("no no no!");
}
if(intval($num,0)===4476){
echo $flag;
}else{
echo intval($num,0);
}
}
- 关于intval(),intval(a,b)将a视为b进制下的数,若b为0或为空时,b的值却决于a,若a包含0x则b=16,若a以0开头,则b=8,否则b=10,当b=10时a自动取整数部分,同时在此函数下1===+1
- 数不能是4476,经过intval()处理后为4476,可以用4476的8进制或16进制或小数
3
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num'])){
$num = $_GET['num'];
if($num==="4476"){
die("no no no!");
}
if(preg_match("/[a-z]/i", $num)){
die("no no no!");
}
if(!strpos($num, "0")){
die("no no no!");
}
if(intval($num,0)===4476){
echo $flag;
}
}
- strpos(a,b)查找a在b中第一次出现的位置,无论是第一位还是找不到都返回false
- 过滤了8进制和16进制,同时必须有0,考虑小数加0
4
<?php
include("flag.php");
highlight_file(__FILE__);
if (isset($_POST['a']) and isset($_POST['b'])) {
if ($_POST['a'] != $_POST['b'])
if (md5($_POST['a']) === md5($_POST['b']))
echo $flag;
else
print 'Wrong.';
}
- md5()函数不能处理数组,数组返回null
- post a[]=1&b[]=2
5
<?php
highlight_file(__FILE__);
include("flag.php");
if(isset($_POST['v1']) && isset($_GET['v2'])){
$v1 = $_POST['v1'];
$v2 = $_GET['v2'];
if(sha1($v1)==sha1($v2)){
echo $flag;
}
}
- 需要同时get和post
- 地址栏get,hackbar post
6
<?php
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
if(isset($_POST['v1'])){
$v1 = $_POST['v1'];
$v3 = $_GET['v3'];
parse_str($v1,$v2);
if($v2['flag']==md5($v3)){
echo $flag;
}
}
- parse_str(a,b),将a中的x=y放入b数组中,b[y]=x,
- 查得admin的md5值为21232f297a57a5a743894a0e4a801fc3,传入admin与flag=21232f297a57a5a743894a0e4a801fc3(不需要加括号)即可
7
<?php
highlight_file(__FILE__);
error_reporting(0);
include("flag.php");
if (ereg ("^[a-zA-Z]+$", $_GET['c'])===FALSE) {
die('error');
}
//只有36d的人才能看到flag
if(intval(strrev($_GET['c']))==0x36d){
echo $flag;
}
- strrev()函数将字符串反转,strrev()与正则匹配类似
- ereg()函数匹配相当于设置白名单,可以被%00截断
- 16进制转换后为877,要求输入全为字母,可以?c=a%00778
8-1
<?php
error_reporting(0);
highlight_file(__FILE__);
class SYC
{
function __wakeup(){
die("private class");
}
static function getFlag(){
echo file_get_contents("flag.php");
}
}
call_user_func($_POST['vanzy']);
- call_user_func(),一共有4种回调方法(注意单引号)
- call_user_func('函数名','传入参数')回调函数
- call_user_func('类名'::'函数名')回调类中的静态方法(注意函数不加括号)
- call_user_func(array(类名,'say_hello'))数值数组回调
- $myobject = new myclass(); call_user_func(array($myobject, '函数'))对象回调
- 这里使用静态方法回调,call_user_func(SYC::getFlag)(注意此echo打印到页面代码中而不是页面上)(也可以数值数组回调)
8-2
<?php
error_reporting(0);
highlight_file(__FILE__);
class ctfshow
{
function __wakeup(){
die("private class");
}
static function getFlag(){
echo file_get_contents("flag.php");
}
}
if(strripos($_POST['ctfshow'], ":")>-1){
die("private function");
}
call_user_func($_POST['ctfshow']);
- sql可以字符串拼接 是因为 sql语句本身是一个字符串,而php中除了部分函数,不能将传递的字符串当代码执行
- strripos(a,b)查找a在b中最后一次出现的位置,所以过滤了:,故使用8中的数值数组回调,所以传入ctfshow[0]=ctfshow&ctfshow[1]=getflag(必须从0(数组第一位)开始传,默认从第一位开始读,第一位为空出问题)
9
<?php
include "flag.php";
error_reporting(0);
highlight_file(__FILE__);
$_403 = "Access Denied";
$_200 = "Welcome Admin";
if ($_SERVER["REQUEST_METHOD"] != "POST")
{
die("BugsBunnyCTF is here :p…");
}
if ( !isset($_POST["flag"]) )
{
die($_403);
}
foreach ($_GET as $key => $value)
{
$$key = $$value;
}
foreach ($_POST as $key => $value)
{
$$key = $value;
}
if ( $_POST["flag"] !== $flag )
{
die($_403);
}
echo "This is your flag : ". $flag . "\n";
die($_200);
?> BugsBunnyCTF is here :p…
- $SERVER["REQUEST_METHOD"] != "xxx"判定请求方式,
- $$a,是指把$a的值作为$的变量名称
- if ( !isset($ -POST["flag"]) )将flag值给覆盖了,推演foreach函数,发现此函数的作用是,将a[x]=y中x与y作为两个变量名并且使之相等,flag值被覆盖打印出来没有,考虑将利用foreach函数将flag值传递给403或者200,get ?_200=flag,post flag=a(此处应传入数组,方法见上)
10
<?php
include "flag.php";
error_reporting(0);
highlight_file(__FILE__);
extract($_GET);
if (isset($gift))
{
$content = trim(file_get_contents($flag));
if ($gift == $content)
{
echo $flag;
}
else
{
echo 'Oh..';
}
}
- extract()函数,依次创建许多变量,把数组中的key当作变量名,值当作变量值
- trim()(同文件包含trim)移除两端空白字符
- 如果直接修改变量相等,content=trim(file_get_contents($flag)); 会将content覆盖,所以把flag值设置为null,使此条语句失效,所以?flag=&gift=(此应为正确解答,但实际结果为只需传?gift= 即可,两者一起传反而不行)
unr
<?php
include("./flag.php");
class one {
public $object;
public function MeMeMe() {
array_walk($this, function($fn, $prev){
if ($fn[0] === "CTF" && $prev === "twotwo") {
global $talk;
echo "$talk"."</br>";
global $flag;
echo $flag;
}
});
}
public function __destruct() {
@$this->object->add();
}
public function __toString() {
return $this->object->string;
}
}
class second {
protected $filename;
protected function addMe() {
return "Wow you have True".$this->filename;
}
public function __call($func, $args) {
call_user_func([$this, $func."Me"], $args);
}
}
class third {
private $string;
public function __construct($string) {
$this->string = $string;
}
public function __get($name) {
$var = $this->$name;
$var[$name]();
}
}
if (isset($_POST["hack"])) {
$a=unserialize($_POST['hack']);
throw new Exception("You are Failed");
} else {
highlight_file(__FILE__);
}
-
函数serialize()和unserialize()是序列化和反序列,将变量转换为可保存或传输的字符串的过程;反序列化就是在适当的时候把这个字符串再转化成原来的变量使用
-
throw new Exception()相当于echo,用于报错
-
array_walk()函数有不超过3个参数,array_walk(数组名(必须),函数名(必须),额外传入参数),要求对应的函数有相等的传参接口,且对应顺序如下(奇奇怪怪的对应顺序):
a=array({1=>q,2=>w); function b($one,$two,$three) { echo "$one $two $three
"; } array_walk($a,"b","c");//数组中的1(key)对应函数的two,数组中的q(key的value)对应函数的one,c对应three -
上述函数的一个奇怪的用法(已理解)
";echo $prev."
";}); }//$this指针在未被指向具体属性的时候就会遍历所有属性,此处只有一个属性,所有$this就是指向$key,同时$this自己表示对象(此处应实验验证) } $a=new one(); $a->aa(); ?> 输出: value key- 先列出魔术方法
本题目中有这些魔术方法可以利用(总结见task6报告) public function __destruct()//退出one类时触发 public function __toString()//任意类中对象当做字符串的时候会被调用。 public function __call($func, $args)//任意类中调用了不存在的函数时触发 public function __construct($string)//进入third类中时被调用。 public function __get($name)//任意类中从不可访问或不存在的属性读取数据时被调用
-
找开头结尾
(网上的)首部 --> one::destruct() --> second::call() --> second::addMe() --> one::toString() --> third::get() --> one::MeMeMe() --> 尾部(疑问:mememe()是public的为什么不直接实例化one的mememe函数)
-
不可见字符?gc利用?系统学习task6反序列化漏洞后重新做这道题