|
这段代码所做的就是看看是否定义了用户。如果没有定义用户,增添的第一个 用户就自动得到管理员权限(Status=Administrator)和安全级别100。在这之后, 再定义的所有用户就只能得到普通用户权限(Status=User)了。所以我们要做的 就是要找到一种方法使得我们的Status=Administrator。我们可以再看看一条用户 记录的详细情况,如下:
# ------------------------------ # Put the user into the database my $Status_q = $dbh -> quote($Status); $Username_q = $dbh -> quote($Username); my $Email_q = $dbh -> quote($Email); my $Display_q = $dbh -> quote($config{’postlist’}); my $View_q = $dbh -> quote($config{’threaded’}); my $EReplies_q = $dbh -> quote("Off"); $query = qq! INSERT INTO Users (Username,Email,Totalposts,Laston,Status,Sort, Display,View,PostsPer,EReplies,Security,Registered) &#118alueS ($Username_q,$Email_q,0,$date,$Status_q,$config{’sort’}, $Display_q,$View_q,$config{’postsperpage’},$EReplies_q,$Security,$date) !;
现在,我得花点时间来解释一下quote()函数。当把一个值为"blah blah blah" 的字符串放入"SELECT * FROM table WHERE data=$data"时,它会成为如下样子:
SELECT * FROM table WHERE data=blah blah blah
这个SQL语句是无效的。数据库只认第一个blah,而不知道怎么处理后边的两个blah。 所以所有的字符串数据应该被压缩进单引号里(’)。因此,查询命令应该像这样:
SELECT * FROM table WHERE data=’blah blah blah’
这才是正确的。在我以前写的SQL安全的文章里提到过一种方法,就是使用我们自己 的单引号来打破SQL语句中的单引号。所以如果我们提交"blah blah’ MORE SQL COMMANDS.." 它看起来应该是下面这个样子:
SELECT * FROM table WHERE data=’blah blah’ MORE SQL COMMANDS...’ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 我们提交的数据
这将使得SQL引擎把MORE SQL COMMANDS解释为实际的SQL命令,因为它把data中的第 二个单引号(我们提交的那个)当作了字符串的结束符。这是把数据转化为是人们易于 阅读的字符串的缺陷,它使得可以重解析数据...所以SQL引擎很难分辨出哪些是数据, 哪些是命令。
这对我们来说是非常有用的。如果提交一个 ’’,它并不是告诉SQL引擎这是字符串 的结尾,而是把它当作字符串中的一个单引号。因此如下的查询命令:
SELECT * FROM table WHERE data=’data’’more data’
会使得数据库去查找"data’more data"的值。所以为了避免用户突破字符串而去提 交额外的命令,程序员应该做的就是复制两个单引号(把 ’变成 ’’)。这能够确保提交 的数据是合法数据。这也正是DBI->quote()函数所做的——把字符串两边加上单引号, 并把用户提交的单引号复制成两个单引号。
在解释了上面这些之后,你应该明白了所有经过了quote()函数处理过的数据就不能 被利用了,因为我们无法提交额外的SQL命令或者篡改其它有用的东西了。如果你看看源 代码会发现,wwwthreads非常广泛的使用了quote()函数,这对我们来说非常不好,但是 还有机会...
你可以看到,域有不同的类型,包括字符串、布尔类型、多种数字类型等。字符串域 需要使用field=’data’这样的格式,而数字域则不用(例如,numeric_field=’2’是错误 的)。正确的数字域的用法应该是numeric_field=2。啊哈!这儿没有单引号,程序甚至 不能随意的加单引号。正确的解决办法是确保所有的数字域是真正的数字(一会儿会详细 解释)。我可以给你个提示,wwwthreads没有进行正确的检查,实际上大多数应用程序也 都没有进行正确的检查。
所以,我们现在要提交一个能够篡改我们感兴趣的表的SQL语句。一个SELECT语句是 固定的,因此我们还需要另外一句其它的SQL语句。INSERT和UPDATE就不错,因为它们已经 可以修改数据了...我们要修改更多的数据(希望如此)。
查找了半天之后,我发现一个非常好的可以利用的地方...changeprofile.pl。这是 一个用来把数据传递给editprofile.pl并把改动写进数据库的程序。当然,改动的只是 我们的用户的数据。这意味着要利用它,就必须注册一个用户。甭管怎么样,让我们先来 看一看:
# Format the query words my $Password_q = $dbh -> quote($Password); my $Email_q = $dbh -> quote($Email); my $Fakeemail_q = $dbh -> quote($Fakeemail); my $Name_q = $dbh -> quote($Name); my $Signature_q = $dbh -> quote($Signature); my $Homepage_q = $dbh -> quote($Homepage); my $Occupation_q = $dbh -> quote($Occupation); my $Hobbies_q = $dbh -> quote($Hobbies); my $Location_q = $dbh -> quote($Location); my $Bio_q = $dbh -> quote($Bio); my $Username_q = $dbh -> quote($Username); my $Display_q = $dbh -> quote($Display); my $View_q = $dbh -> quote($View); my $EReplies_q = $dbh -> quote($EReplies); my $Notify_q = $dbh -> quote($Notify); my $FontSize_q = $dbh -> quote($FontSize); my $FontFace_q = $dbh -> quote($FontFace); my $ICQ_q = $dbh -> quote($ICQ); my $Post_Format_q= $dbh -> quote($Post_Format); my $Preview_q = $dbh -> quote($Preview);
靠!几乎所有的参数都被quote()处理过了。这表示所有这些参数对我们来说就都 没用了。让我们再来看看最终被写进数据库的查询语句:
# Update the User’s profile my $query =qq! UPDATE Users SET Password = $Password_q, Email = $Email_q, Fakeemail = $Fakeemail_q, Name = $Name_q, Signature = $Signature_q, Homepage = $Homepage_q, Occupation = $Occupation_q, Hobbies = $Hobbies_q, Location = $Location_q, Bio = $Bio_q, Sort = $Sort, Display = $Display_q, View = $View_q, PostsPer = $PostsPer, EReplies = $EReplies_q, Notify = $Notify_q, TextCols = $TextCols, TextRows = $TextRows, FontSize = $FontSize_q, FontFace = $FontFace_q, Extra1 = $ICQ_q, Post_Format = $Post_Format_q, Preview = $Preview_q WHERE Username = $Username_q !;
因为wwwthreads自动在用quote()处理过的变量后面加了“_q”,所以我们很容易 看出来。可以看到:$Sort, $PostsPer, $TextCols, 和 $TextRows 没有被quote()处 理过。现在让我们来看看这些变量出自哪里。
my $Sort = $FORM{’sort_order’}; my $PostsPer = $FORM{’PostsPer’}; my $TextCols = $FORM{’TextCols’}; my $TextRows = $FORM{’TextRows’};
喔,它们是直接从用户提交的数据里解析出来的。这意味着它们没有经过任何有效 性检查,这就是我们可以利用的机会了!
在回过头来看看用户记录的结构(前面已给出),我们所要改变的是’Status’域。 在这个UPDATE查询中,Status并没有被列出。这意味着Status会保持不变。那么我们 怎么办呢?花1秒中时间想一下。
上一页 [1] [2] [3] [4] 下一页 |