NeSE三月升级赛WriteUp (Web)

又是一个XSS题,Docker里起了一个Web一个Bot一个Redis,Web使用Java写的,用的Eclipse的Jetty服务器,上层是Micronaut微服务框架来的,整体打包成一个JAR。 附件地址:CTF-Chal/fancy-notes.zip (github.com) 一开始还以为是Java相关的漏洞,随手看了下反编译,发现好像除了题目是Java写的之外和Java没啥关系,同理Redis也只是个用来传数据的中间媒介,似乎也利用不了什么漏洞。于是继续关注题目本身的逻辑。 先看Bot做了啥: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 const puppeteer = require("puppeteer"); const Redis = require('ioredis'); const connection = new Redis(6379, process....

Mar. 19, 2023 · 7 min · 1362 words

HXPCTF 2023 Web复现

valentine Web签到题,考的是Node.js的ejs模板库命令执行。首先给出源码,里面的库版本都是最新的: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 var express = require('express'); var bodyParser = require('body-parser') const crypto = require("crypto"); var path = require('path'); const fs = require('fs'); var app = express(); viewsFolder = path....

Mar. 12, 2023 · 5 min · 978 words

NeSE十二月升级赛WriteUp (Web)

一个硬核的XSS题,收获相当大(还得感谢CrumbledWall师傅点拨了我几次) 开局给了后端的源码,能看见里面用了腾讯的COS对象存储,可以上传文件到上面,docker-compose.yml里面还有一个名为的bot的服务但没有给出源码,能看出来后端有个接口会去连接这个bot。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 const express = require("express") const isJpg = require('is-jpg') const isPng = require('is-png') const isWebp = require('is-webp') const fs = require('fs') const fileUpload = require('express-fileupload') const bodyParser = require('body-parser') const net = require('net') const crypto = require("crypto") const https = require('https') var COS = require('cos-nodejs-sdk-v5') const app = express() const BOT_HOST = 'bot' const BOT_PORT = 8080 app....

Dec. 20, 2022 · 6 min · 1267 words

N1CTF 2022 Web 复现

Easy_S2 这题主要考察的是Struts2的路径匹配规则以及Java Web中的Security-Constraint安全约束选项。题目附件是一个.war包,将其解压之后可以直接通过Tomcat部署,代码实现也很简单。通过web.xml可以了解到整个网站的路由都被导向了中间Struts2,同时有两条安全约束项: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <!-- 整个网站的路由都由Struts2处理 --> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- /img/* 和 /index.jsp 不需要认证即可访问 --> <security-constraint> <display-name>pass-static</display-name> <web-resource-collection> <web-resource-name>static</web-resource-name> <url-pattern>/img/*</url-pattern> <url-pattern>/index....

Nov. 21, 2022 · 8 min · 1642 words

NeSE十月升级赛WriteUp (Web)

学到了一些SQL注入的新姿势~ ezweb 首先是一个登录页,随便输入后发现会显示出查询数据库的具体语句: 于是想到可能有注入,试了一下万能密码admin' or 1=1 -- ,竟然成功进去了 登进去之后发现一个修改个人信息的功能点,可以上传头像: 尝试传个一句话上去,但发现存在后缀名的黑名单,和PHP相关的后缀名不是被ban了就是没解析,其他格式也不会被解析。还搜了一下,PHP在FashCGI模式下,也支持类似Apache里面.htaccess的独立配置文件用法,可以在某个文件夹创建一个名为.user.ini的配置文件,该配置仅对当前目录生效。但后面又发现.ini也被ban了……所以也没法通过修改解析格式的方式来解析脚本了(具体.user.ini能不能修改解析方式也没有去深究,找个时间研究一下) 除此之外,发现文件内容也会被替换,比如?会被替换成!,使得PHP起始的标签没法构造: 不过其他的过滤倒也没有,可以使用<script language="php"></script>来绕过PHP标签的过滤,来写入一句话。 一句话传上去了,接下来就想着怎么执行。因为无论怎么传也没法解析,黑名单也没法绕过,于是想到是不是可能有其他的包含点,翻源码翻来翻去,在用户列表的页面里找到了一个小提示,果然有包含点: 然后就是直接包含上传的一句话,执行命令cat /flagaaaaaaaaaaaa拿到Flag: sqli 一道很直白的SQL注入题,随便试了一下发现有报错,根据报错信息可以知道传参外面是包裹了一层单引号的。尝试了不少关键词都显示hack,于是首先fuzz了一下黑名单,发现过滤的有亿点多: 除去常见的关键字外,还过滤了下面这几类: 所有的空白字符,包括空格、\n、\t、\x00等; 所有的注释符(//除外但并不能注释成功); information_schema; 逻辑运算&&、||、OR; 时间盲注相关:sleep、benchmark; 字符串截取函数substr、substring、mid、left、right; …… 对于空格的绕过,可以使用括号来括住表达式,这样可以不使用空格;但测试了一波之后,发现虽然UNION SELECT没有被过滤,但因为无法使用注释符,使得尾部的单引号无法被注释导致UNION SELECT无法构造成功。联合注入就走不通了。 遂尝试布尔盲注,首先子字符串的截取函数被ban,但又需要找到个办法来判断子字符串,翻了翻手册找到了locate函数,虽然没法截取字符串直接返回,但可以返回指定子字符串的索引值,似乎是个曲线救国的办法: LOCATE(substr,str), LOCATE(substr,str,pos) The first syntax returns the position of the first occurrence of substring substr in string str. The second syntax returns the position of the first occurrence of substring substr in string str, starting at position pos. Returns 0 if substr is not in str....

Oct. 3, 2022 · 3 min · 474 words

ByteCTF 2022 WriteUp

感觉可以抽个时间专门再学学SQL注入了… Web easy_grafana 打开题目,Grafana v8.2.6,经典CVE-2021-43798,但是原始的POC没法用,返回400,后来查了一下发现可能是中间件对URL做了标准化导致没法打,在POC中添加#可以顺利绕过。 读取配置文件/etc/grafana/grafana.ini,发现SecretKey: 1 secret_key = SW2YcwTIb9zpO1hoPsMm 然后就是脱裤/var/lib/grafana/grafana.db,在data_source表中的secure_json_data列中找到加密后的登录密码: 1 {"password":"b0NXeVJoSXKPoSYIWt8i/GfPreRT03fO6gbMhzkPefodqe1nvGpdSROTvfHK1I3kzZy9SQnuVy9c3lVkvbyJcqRwNT6/"} 随便Github找了个脚本解密即可: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 import base64 from hashlib import pbkdf2_hmac from Crypto....

Sep. 25, 2022 · 5 min · 917 words

T-Star CTF 2022 WriteUp

赛后复盘发现感觉自己脑洞还是不够大。。。里面的Web题虽然难度不大但还是学到了一些零零碎碎的知识点 关卡1 给了一个URL,打开后显示需要输入手机号获取验证码,随便打了一个发现发送验证码的接口有Debug信息直接把验证码返回了: 输入验证码后进入网站,就一个十分简陋的网站,有四个直播间页面,都在放TSRC的宣传视频hhh,然后扫接口在点赞的地方找到了一个XXE(赛后复盘的时候站已经关了,放一张当时的截图) 总之当时就是发现可以本地读取文件但是没有回显,而且像上图加载进XML的数据还是会被带进后端查询直播的用户,如图中/sys/kernel/fscaps的值是1,带进去能够找到用户ID为1的用户所以返回500,如果没找到就返回No such streamer的消息。又试了几回发现没法加载远程DTD文件,于是当时就放着没管了 赛后看wp学到了一个没见过的操作就是基于XML报错的XXE,https://j7ur8.github.io/WebBook/PHP/报错XXE.html,感觉原理就是把远程加载的东西直接写进了ENTITY里面,但是因为变量解析的原因需要嵌套包含两三层,最终的结果就是把要读取的文件读到了exp字符串里面,然后尝试去包含带有错误字符串的文件产生报错,在报错信息里也就会输出文件的内容。 1 2 3 4 5 6 7 8 9 10 11 <?xml version="1.0" ?> <!DOCTYPE message [ <!ENTITY % condition ' <!ENTITY &#x25; file SYSTEM "file:///etc/passwd"> <!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>"> &#x25;eval; <!-- 把报错的ENTITY通过引用加载进来 --> &#x25;error; <!-- 引用会产生报错的ENTITY error, 然后error会去加载里面的file引用实体内容,从而产生一个错误的URI --> '> %condition; ]> <message>any text</message> 通过这种方法,结合proc就能够读到后端的代码/proc/self/cwd/app.py,然后发现模块config,读取config.py拿到flag。 关卡2 大概是个社工题吧,社工第一题网站里的直播ID:nightbaron042,但因为腾讯总部在深圳所以蒙了个深圳,就过了hhh 关卡3 附件是一个流量包,是一个TCP的流量,追踪了一下数据流很容易发现是ADB Shell的流量,里面对一个名为ctf.misc.step的apk包进行了备份: 搜索了一番发现利用https://github.com/nelenkov/android-backup-extractor工具可以解密Android Backup文件,于是将二进制数据dump下来,用16进制编辑器敲掉多余的数据后尝试解密,发现要密码: 于是又去流量包里追踪了其他的流,发现后面开了一下ADB Shell,有cat pass的操作,获得密码: 解压备份数据后得到以下文件: OpenSSL用私钥解一下key.en可以得到压缩包的密码,得到一个txt,排版后发现是个二维码...

Apr. 24, 2022 · 4 min · 664 words

*CTF 2022 WriteUp

虽然比赛时只做出来一道题,但确实玩的挺开心的,所以记录一下 oh-my-grafana 该题用到了Grafana应用中最为广泛的一个CVE漏洞CVE-2021-43798,可以未授权通过Grafana的插件实现任意文件读取。 通过搜索获取到Grafana的配置文件路径/etc/grafana/grafana.ini,在里面翻到了管理员的帐号和密码(一开始我还以为不会这么简单,还去读取了一下Grafana的数据库,/var/lib/grafana/grafana.db) 然后利用后台的数据库查询工具,查询Grafana的数据库获得flag。 oh-my-notepro 打开网站后是一个简单的笔记界面,创建账户登录进去之后就可以写笔记并且查看笔记: 点进去笔记详情页,很容易发现URL格式为/view?note_id=at8k8cdp6874vqcvzifietexy4gtnpey,尝试修改为不存在的note_id,产生报错,发现后端是Flask而且开启了调试模式,查看错误代码发现是SQL查询错误: 于是尝试注入,发现轻松注进去,没有任何过滤: 但是翻看了一阵子数据库之后发现没什么有用的信息,且数据库为USAGE权限所以没法提权。翻看了一下其他的功能点,整个网站的功能也十分单一并没有发现额外的功能,所以接着把关注点放在了Flask的调试模式上。 注意到在报错代码的右侧有个小按钮,名为Open an interactive python shell in this frame,也就是可以直接起一个Python shell,但是需要一个Debug PIN才能解锁。 于是搜索发现这个PIN可以直接生成,参考文章https://www.daehee.com/werkzeug-console-pin-exploit/。文章中提到这个PIN是由四个公共变量和两个私有变量经过哈希生成的,也就是下面这一段: 1 2 3 4 5 6 7 8 9 10 11 probably_public_bits = [ 'web3_user',# username 'flask.app',# modname 'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__')) '/usr/local/lib/python3.5/dist-packages/flask/app.py' # getattr(mod, '__file__', None), ] private_bits = [ '279275995014060',# str(uuid.getnode()), /sys/class/net/ens33/address 'd4e6cb65d59544f3331ea0425dc555a1'# get_machine_id(), /etc/machine-id ] probably_public_bits中的用户名和Flask包路径分别在数据库和调试信息中可以获取到,接下来就剩下这两个私有的变量需要读取对应的文件才能获取到。一开始尝试用MySQL的LOAD_FILE来包含文件但是一直返回空值,赛后经群友指点学到了一个新的MySQL语法LOAD DATA(https://dev.mysql.com/doc/refman/5.7/en/load-data.html),可以直接将文件中的数据读取至表中。因为这个语句没法制定读进哪个列,所以读进已有的表似乎可能性不大(第一列都是ID,数据类型一转换就没了),尝试创建一个新表,发现可以创建,于是通过写入新表的方式可以获取到这些信息,Payload如下: 1 2 3 4 /view?note_id=';create table test(`name` varchar(4096) null)--+ /view?...

Apr. 17, 2022 · 2 min · 424 words