Eleven
docker 又拉取失败
这不是11题嘛 为啥copy 10
解决方法:
在根目录创建 challenge10.php 代码改成11题的代码就好了
1 |
|
全局使用的值 _REQUEST[‘hello’];
正则匹配
if(!preg_match(‘/^\w*a )){
die(‘ERROR’);
}
要求hello的输入必须为数字 和 字母
eval(“var_dump($$a);”);
show_source(FILE);
存在eval()函数,查看是否可以进行闭合var_dump(),造成命令执行。
存在过滤了符号,无法闭合,所以不能通过闭合var_dump()造成命令执行。
不过,发现var_dump()中存在$$a,可以输出对应的变量值,但是需要指定包含flag文件里面的变量值
但是》》》
PHP中还存在一个特殊的变量,引用全局作用域中可用的全部变量:
$GLOBALS
使用var(%20%20%E7%9A%84%E4%BE%8B%E5%AD%90%3Cbr%20%2F%3E!%5Bimage.png%5D(https%3A%2F%2Fcdn.nlark.com%2Fyuque%2F0%2F2023%2Fpng%2F22356351%2F1679281075329-e7b4d1d6-37df-4847-8164-d1a29fbd5a2d.png%23averageHue%3D%2523b09b50%26clientId%3Du1ce9842f-122a-4%26from%3Dpaste%26height%3D1050%26id%3Du7081636c%26name%3Dimage.png%26originHeight%3D1050%26originWidth%3D1955%26originalType%3Dbinary%26ratio%3D1%26rotation%3D0%26showTitle%3Dfalse%26size%3D444807%26status%3Ddone%26style%3Dnone%26taskId%3Du2ca27eaf-d57e-41aa-85bd-944fb7962fa%26title%3D%26width%3D1955)%3Cbr%20%2F%3E%E8%BF%99%E6%A0%B7%E5%AD%90%E5%B0%B1%E5%8F%AF%E4%BB%A5dump%20%E5%87%BA%20include%20%E5%8C%85%E5%90%AB%E7%9A%84%E6%96%87%E4%BB%B6%E4%BA%86%20%3Cbr%20%2F%3E%E5%85%B6%E4%B8%ADglobal%E5%92%8C#card=math&code=GLOBALS%29%20%20%E7%9A%84%E4%BE%8B%E5%AD%90%3Cbr%20%2F%3E%21%5Bimage.png%5D%28https%3A%2F%2Fcdn.nlark.com%2Fyuque%2F0%2F2023%2Fpng%2F22356351%2F1679281075329-e7b4d1d6-37df-4847-8164-d1a29fbd5a2d.png%23averageHue%3D%2523b09b50%26clientId%3Du1ce9842f-122a-4%26from%3Dpaste%26height%3D1050%26id%3Du7081636c%26name%3Dimage.png%26originHeight%3D1050%26originWidth%3D1955%26originalType%3Dbinary%26ratio%3D1%26rotation%3D0%26showTitle%3Dfalse%26size%3D444807%26status%3Ddone%26style%3Dnone%26taskId%3Du2ca27eaf-d57e-41aa-85bd-944fb7962fa%26title%3D%26width%3D1955%29%3Cbr%20%2F%3E%E8%BF%99%E6%A0%B7%E5%AD%90%E5%B0%B1%E5%8F%AF%E4%BB%A5dump%20%E5%87%BA%20include%20%E5%8C%85%E5%90%AB%E7%9A%84%E6%96%87%E4%BB%B6%E4%BA%86%20%3Cbr%20%2F%3E%E5%85%B6%E4%B8%ADglobal%E5%92%8C&id=S96IB)GLOBALS的区别:
$GLOBALS[‘var’]是外部全局变量的本身,而global var的同名引用或者说是指针,也就是说global函数产生一个指向函数外部变量的别名变量,而不是真正的函数外部变量,而$GLOBALS[]确确实实调用的是外部的变量,函数内外都会始终保持一致。
所以payload :
直接引用$GLOBALS
然后eval执行var_dump(GLOBALS) ;
就dump 出flag了 ;
Twelve
老出错 。。。
和上一题很像啊
直接输出了GLOBALS超全局变量进行遍历,也没有过滤啥。
考虑闭合var_dump($a)函数并构造其他的语句进行执行
eval函数
eval() 函数把字符串按照 PHP 代码来计算。
该字符串必须是合法的 PHP 代码,且必须以分号结尾return 语句会立即终止对字符串的计算。
返回值: 除非在代码字符串中调用 return 语句,则返回传给 return 语句的值,否则返回 NULL。如果代码字符串中存在解析错误,则 eval() 函数返回 FALSE。
var_dump函数
var_dump() 函数用于输出变量的相关信息。
var_dump() 函数显示关于一个或多个表达式的结构信息,包括表达式的类型与值。数组将递归展开值,通过缩进显示其结构。
print_r() 函数用于打印变量,以更容易理解的形式展示。
PHP 版本要求: PHP 4, PHP 5, PHP 7
file() 函数把整个文件读入一个数组中。
数组中的每个元素都是文件中相应的一行,包括换行符在内。
语法
file(path,include_path,context)
直接闭合打印flag.php 文件
payload :
?hello=);print_r(file(“flag.php”));//
这里可以使用var_dump 也可以使用 print_r
?hello=);var_dump(file(“flag.php”));//
Thirteen
函数分析:
mt_srand()
mt_srand() 播种 Mersenne Twister 随机数生成器。
注释:自 PHP 4.2.0 起,不再需要用 srand() 或 mt_srand() 函数给随机数发生器播种,现已自动完成。
PHP随机函数
PHP随机函数主要有rand、mt_rand、array_rand,还有随机”排列”(打乱顺序)的函数shuffle、str_shuffle,以及能够产生唯一ID的uniqid。
1、rand()
• rand()函数返回随机整数。
• 如果没有提供可选参数 min 和 max,rand() 返回 0 到 RAND_MAX 之间的伪随机整数。例如,想要 5 到 15(包括 5 和 15)之间的随机数,用 rand(5, 15)。
• rand()函数是使用libc的随机数发生器生成随机数的,一般较慢,且有不确定因素。
• 其中getrandmax()函数可以返回rand函数能够产生的最大的随机数,在设置rand()函数第二个参数时可以设置为getrandmax()的返回值。
mt_rand()函数
• mt_rand() 使用 Mersenne Twister 算法返回随机整数。
• 如果没有提供可选参数 min 和 max,mt_rand() 返回 0 到 RAND_MAX 之间的伪随机数。例如想要 5 到 15(包括 5 和 15)之间的随机数,用 mt_rand(5, 15)。
• 很多老的 libc 的随机数发生器具有一些不确定和未知的特性而且很慢。PHP 的 rand() 函数默认使用 libc 随机数发生器。mt_rand() 函数是非正式用来替换它的。该函数用了 Mersenne Twister 中已知的特性作为随机数发生器,它可以产生随机数值的平均速度比 libc 提供的 rand() 快四倍。
• 注释:自 PHP 4.2.0 起,不再需要用 srand() 或 mt_srand() 函数给随机数发生器播种,现在已自动完成。
array_rand()函数
• array_rand() 函数返回数组中的随机键名,或者如果您规定函数返回不只一个键名,则返回包含随机键名的数组。
• array_rand() 函数从数组中随机选出一个或多个元素,并返回。
• 第二个参数用来确定要选出几个元素。如果选出的元素不止一个,则返回包含随机键名的数组,否则返回该元素的键名。
shuffle()函数
• shuffle() 函数把数组中的元素按随机顺序重新排列。
• 该函数为数组中的元素分配新的键名。已有键名将被删除。
str_shuffle()函数
• str_shuffle() 函数随机打乱字符串中的所有字符。
uniqid()函数
• uniqid() 函数基于以微秒计的当前时间,生成一个唯一的 ID。
• 语法:
uniqid(prefix,more_entropy)
• 如果 prefix 参数为空,则返回的字符串有 13 个字符串长。如果 more_entropy 参数设置为 true,则是 23 个字符串长。
• 如果 more_entropy 参数设置为 true,则在返回值的末尾添加额外的熵(使用组合线形同余数生成程序),这样可以结果的唯一性更好。
• 返回值:以字符串的形式返回唯一标识符。
• 注释:由于基于系统时间,通过该函数生成的 ID 不是最佳的。如需生成绝对唯一的 ID,请使用 md5() 函数。
• 如果单独使用uniqid()方法,不带任何参数的话,这个方法只能保证单个进程,在同一个毫秒内是唯一的。如果使用uniqid(“”,true),带了一个墒值,自身已经有一个随机的方法能保证生成的id的随机性。但是由于线性同余是比较简单的生成随机数的算法,随机性有可能还不够。
所以大多数采用的方法为:
nuiqid(mt_rand(), true)
主要代码 :
1 |
|
其中参数whoami要满足两个条件,一个是满足whoami输入的值与产生的随机值相等,另一个条件就是要满足md5(%E4%BB%8E%E7%AC%AC%E4%BA%94%E4%BD%8D%E5%8F%96%EF%BC%8C%E5%8F%96%E5%9B%9B%E4%BD%8D%EF%BC%8C%E8%83%BD%E5%A4%9F%3D%3D0%EF%BC%8C%E5%85%B6%E4%B8%AD%E5%90%8E%E4%B8%80%E4%B8%AA%E6%9D%A1%E4%BB%B6%E5%85%B6%E5%AE%9E%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87PHP%E7%9A%84%E5%BC%B1%E6%AF%94%E8%BE%83%E6%9D%A5%E8%BF%9B%E8%A1%8C%E5%88%A9%E7%94%A8%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E5%8F%AA%E8%A6%81%E4%BF%9D%E8%AF%81%E7%AC%AC%E4%BA%94%E4%BD%8D%E5%80%BC%E4%B8%BA%E5%AD%97%E6%AF%8D%EF%BC%8C%E5%B0%B1%E5%8F%AF%E4%BB%A5%E6%BB%A1%E8%B6%B3(md5(#card=math&code=value%29%E4%BB%8E%E7%AC%AC%E4%BA%94%E4%BD%8D%E5%8F%96%EF%BC%8C%E5%8F%96%E5%9B%9B%E4%BD%8D%EF%BC%8C%E8%83%BD%E5%A4%9F%3D%3D0%EF%BC%8C%E5%85%B6%E4%B8%AD%E5%90%8E%E4%B8%80%E4%B8%AA%E6%9D%A1%E4%BB%B6%E5%85%B6%E5%AE%9E%E5%8F%AF%E4%BB%A5%E9%80%9A%E8%BF%87PHP%E7%9A%84%E5%BC%B1%E6%AF%94%E8%BE%83%E6%9D%A5%E8%BF%9B%E8%A1%8C%E5%88%A9%E7%94%A8%EF%BC%8C%E4%B9%9F%E5%B0%B1%E6%98%AF%E8%AF%B4%EF%BC%8C%E5%8F%AA%E8%A6%81%E4%BF%9D%E8%AF%81%E7%AC%AC%E4%BA%94%E4%BD%8D%E5%80%BC%E4%B8%BA%E5%AD%97%E6%AF%8D%EF%BC%8C%E5%B0%B1%E5%8F%AF%E4%BB%A5%E6%BB%A1%E8%B6%B3%28md5%28&id=hha2C)value),5,4) == 0
这里可以使用MD5无法处理数组的漏洞
还有个条件 :
1 |
|
在120秒内访问10次,条件满足 ,echo flag
payload :
1 |
|
Fourteen
直接把 path 拼接到 include 里面去了可以直接读取文件
先读取一下passwd
但是读取不了 flag文件
使用php://filter协议
php://filter/convert.base64-encode/resource=flag.php
php://filter/read=convert.base64-encode/resource=flag.php
就会输出 flag.php 的base64的编码
文件包含相关函数
include
require
include_once
require_once
highlight_file
show_source
readfile
file_get_contents
fopen
file
PHP伪协议
要满足PHP伪协议,基于函数include和include_once()的利用情况。
另外就是PHP.ini环境问题:
1 |
|
常用伪协议
file:// — 访问本地文件系统
http:// — 访问 HTTP(s) 网址
ftp:// — 访问 FTP(s) URLs
php:// — 访问各个输入/输出流(I/O streams)
zlib:// — 压缩流
data:// — 数据(RFC 2397)
glob:// — 查找匹配的文件路径模式
phar:// — PHP 归档
ssh2:// — Secure Shell 2
rar:// — RAR
ogg:// — 音频流
expect:// — 处理交互式的流
利用条件
1、协议:file://
• 利用条件:allow_url_fopen和allow_url_include双Off情况下可正常使用
• 说明:访问本地文件系统
• 用法:file://文件绝对路径和文件名
2、协议:php://
• 利用条件:不需要开启allow_url_fopen(仅php://input,php://stdin,php://memory和php://temp需要allow_url_include=On)
说明:访问IO流
• 用法:php://input 可以访问请求的原始数据的只读流,将post请求中的数据作为php代码执行。
3、协议:zip://,bzip2://,zlib://
• 利用条件:双Off条件下可使用
• 说明:zip://test.zip#x.txt zip://绝对路径#子文件名
• x.txt内容就会以php代码执行
• compress.bzip2://test.bz2和compress.zlib://test.gz用法相同
• /include.php?file=compress.bzip2://绝对路径/shell.jpg 或者 compress.bzip2://./shell.jpg
• 用法:可以访问压缩文件中的子文件,更重要的是不需要指定后缀名
4、协议:data://
• 利用条件:双On
• 说明:
/include.php?file=data://text/plain,
或者 data://text/plain;base64,PD9waHAgcGhwaW5mbygpPw4=
或者 data:text/plain,
或者 data:text/plain;base64,PD9waHAgcGhwaW5mbygpPw4=
Fifteen
1 |
|
传入两个参数
file=
path=
path会拼接上传的路径 _GET[‘path’];
主要代码是这里
1 |
|
函数解析 :
strpos() f函数查找字符串在另一字符串中第一次出现的位置(区分大小写)。
注释:strpos() 函数是区分大小写的。
注释:该函数是二进制安全的。
相关函数:
- strrpos() - 查找字符串在另一字符串中最后一次出现的位置(区分大小写)
- stripos()- 查找字符串在另一字符串中第一次出现的位置(不区分大小写)
- strripos() -查找字符串在另一字符串中最后一次出现的位置(不区分大小写)
语法
strpos(string,find,start)
所以file开头要等于 http://127.0.0.1/
file_put_contents() 函数把一个字符串写入文件中。
该函数访问文件时,遵循以下规则:
- 如果设置了 FILE_USE_INCLUDE_PATH,那么将检查 filename 副本的内置路径
- 如果文件不存在,将创建一个文件
- 打开文件
- 如果设置了 LOCK_EX,那么将锁定文件
- 如果设置了 FILE_APPEND,那么将移至文件末尾。否则,将会清除文件的内容
- 向文件中写入数据
- 关闭文件并对所有文件解锁
如果成功,该函数将返回写入文件中的字符数。如果失败,则返回 False。
file_get_contents() 把整个文件读入一个字符串中。
该函数是用于把文件的内容读入到一个字符串中的首选方法。如果服务器操作系统支持,还会使用内存映射技术来增强性能。
所以
file_put_contents();
这个代码的意思是,从path中
先输入一个file
出现logsole.log 但是没有路径
再输入第二个参数 path
他就会吧file 写入到1.php
利用ssrf的原理
构造payload
但是这里还要经过二次url编码
是path的内容进行二次编码
Sixteen
1 |
|
只能有数字和字母,但是这里ereg函数存在 %00 截断漏洞
ereg()用途
ereg()函数用指定的模式搜索一个字符串中指定的字符串,如果匹配成功返回true,否则,则返回false。搜索字母的字符是大小写敏感的。
可选的输入参数规则包含一个数组的所有匹配表达式,他们被正则表达式的括号分组。
1 |
|
这里传入的值要大于999999999,但是长度要小于11
采用科学计数法 1e9
1 |
|
hihi前面要有#HONG#
然后前面又要判断只能是数字字母
所以1e9在前 然后使用%00截断 在 把#HONG# 放在%00后面
ereg可被%00截断,ereg识别1e9%00#HONG#到%00就认为字符串已结束,前面的1e9符合正则
payload :
submit=1&hihi=1e9%00#HONG#
Seventeen
又见ereg ,但是这里不是使用截断了
1 |
|
GET= ^_^
^_^ 不能有,0-9,%,http……等等 ,不然 $smile = 0
1 |
|
$_SERVER[“QUERY_STRING”] #查询(query)的字符串
提取自己得的 query字符串
矛盾点:
$_GET数组本身提取自QUERY_STRING,$_GET[‘^_^’]中key包含_符号,而QUERY_STRING 却不允许。
1 |
|
file_exists需要寻找的文件必须不存在、
1 |
|
写入的内容要强等于 (●’◡’●)
绕过
当.或[]之类的符号作为参数的key的时候,会被PHP改写为 _
绕过 if (ereg (‘_’, $_SERVER[‘QUERY_STRING’])) $smile = 0;
file_get_contents可以获取远程数据,但常用网络协议已经被正则过滤,因此需要选取其他协议。
data协议可用,file_exists对于data指向内容判断为不存在
payload :
?^.^=data://text/plain;charset=unicode,(●’◡’●)
$_SERVER的数组信息表
Eighteen
源代码 :
传入参数 :
id
login
name
password
user
1 |
|
传入的user 与 常量$USER进行比较
比较函数strcmp,当strcmp第一个参数小于第二个参数时,返回值为负一,反之为正一,相等时为零。
在不知道常量USER的情况下,满足条件,可以破坏数据结构,参数字符串改成数据,即可得到false值
1 |
|
账号密码不能一致,然后要求 md5 相等 ,可以使用数组绕过
1 |
|
传入id 需要是数字,if中全类型比较,不是72,可以使用小数类型绕过,然后不含空格,输入flag
Payload:
id=72.0&login=Check&name[]=a&password[]=b&user[]=2
Nineteen
条件:
- $sss !== ‘0x666’
- $sss == ‘0x666’ 可知 $sss 的值需要等于数值 0x666,而又不能等于字符串 ‘0x666’,其中涉及PHP的弱类型比较
- if(!preg_match(“/[^0-6]/“,$sss)) $sss只能包含 0–6 的数字
- if(strlen($sss)==666) $sss 的长度等于 666、
使用脚本跑
Twenty
我们直接看后面 if 中的判断逻辑:
- $_GET[‘user’] 是一个全局的变量,我们传的是字符串,它就是字符串,传的是数组,那么它的值就是数组
- $user 是一个数组, [0 => ‘admin’, 1 => ‘xxoo’]
- === 三个等号的意思就是类型是同一类型,并且值也是相同的
- $_GET[‘user’][0] 的值不能等于 ‘admin’
也就是说,如果要使这个 if 条件成立,就必须让两个键值不相等的数组经过 === 比较后返回 true。
4.然后我们测试:
1 |
|
然后我们再来看我们这个漏洞:
1 |
|
键名为 0 的数组与键名为 0x100000000 的数组居然相等了!
也就是说:
1 |
|
这样就能使题目当中的条件成立。
http://localhost:23130/challenge19.php?user[429496729600000000]=admin&user[1]=xxoo