【BugkuCTF】Whois
直接访问http://49.232.142.230:15900/query.php
会直接爆出源码
<?php error_reporting(0); $output = null; $host_regex = "/^[0-9a-zA-Z][0-9a-zA-Z\.-]+$/"; $query_regex = "/^[0-9a-zA-Z\. ]+$/"; if (isset($_GET['query']) && isset($_GET['host']) && is_string($_GET['query']) && is_string($_GET['host'])) { $query = $_GET['query']; $host = $_GET['host']; if ( !preg_match($host_regex, $host) || !preg_match($query_regex, $query) ) { $output = "Invalid query or whois host"; } else { $output = shell_exec("/usr/bin/whois -h ${host} ${query}"); } } else { highlight_file(__FILE__); exit; } ?> <!DOCTYPE html> <html> <head> <title>Whois</title> </head> <body> <pre><?= htmlspecialchars($output) ?></pre> </body> </html>具体执行的命令大概如下所示
/usr/bin/whois -h whois.verisign-grs.com baidu.com但是这里需要绕正则,通过正则可知我们无法使用常规的方法来拼接命令
# host参数只能由0-9、a-z、A-Z、.(点)、-(减号)以及\n或者\r 组成 $host_regex = "/^[0-9a-zA-Z][0-9a-zA-Z\.-]+$/"; # query参数只能由0-9、a-z、A-Z、.(点)、 (空格)以及\n或者\r组成 $query_regex = "/^[0-9a-zA-Z\. ]+$/";可以看到\n换行符和\r回车符是可以用的
\n的url编码是%0a
\r的url编码是%0d
原理是因为正则表达式没有模式符m开启多行搜索,因此不会匹配\n、\r
假设你构造的payload是
host=whois.verisign-grs.com%0a query=ls /preg_match匹配到的内容是
whois.verisign-grs.com而且由于代码中是或关系,只要有一个能匹配成功就可以执行shell_exec
if ( !preg_match($host_regex, $host) || !preg_match($query_regex, $query) ) { $output = "Invalid query or whois host"; } else { $output = shell_exec("/usr/bin/whois -h ${host} ${query}"); }那么到了后端php解析交给linux执行的命令就成了这样,因为\n(%0a) = 强制执行当前命令
这样就执行两条命令
/usr/bin/whois -h whois.verisign-grs.com ls /