Real World CTF 2018 ccls-fringe命题报告

栏目: 服务器 · 编程工具 · 发布时间: 6年前

内容简介:上周日给Real World CTF 2018出了一道forensics题ccls-fringe,向解出此题的31支队伍表达祝贺。上一次出题已是2016年,一直没有人教我pwn、reverse、web所以只能从平常接触的东西里勉强抽出要素弄成题目。kelwya找我来出题,他说forensics也可以,阻止了我说另请高明。另外也想给自己的项目打广告,萌生了从

上周日给Real World CTF 2018出了一道forensics题ccls-fringe,向解出此题的31支队伍表达祝贺。

上一次出题已是2016年,一直没有人教我pwn、reverse、web所以只能从平常接触的东西里勉强抽出要素弄成题目。

kelwya找我来出题,他说forensics也可以,阻止了我说另请高明。另外也想给自己的项目打广告,萌生了从 ccls 的cache弄一道forensics的想法,因为惰性拖了两个星期没有动手。之前一次LeetCode Weekly前在和一个学弟聊天,就想把他的id嵌入了flag。LeetCode第一题Leaf-Similar Trees没有叫成same-fringe,所以我的题目就带上fringe字样“科普”一下吧。

下载 ccls-fringe.tar.xz 后解压得到 .ccls-cache/@home@flag@/fringe.cc.blob 。这是存储的cache文件。

这里体现了ccls和cquery的一个不同点。ccls默认使用 "cacheFormat":"binary" 了,这个自定义的简单序列化格式,cquery仍在使用JSON。

写段程序读入文件,用 ccls::Derialize 反序列化成 IndexFile ,用 ToString 可以转成JSON字串,阅读可以发现其中一个变量 int b

{
  "usr": 7704954053858737267,
  "detailed_name": "int b",
  "qual_name_offset": 4,
  "short_name_offset": 4,
  "short_name_size": 1,
  "hover": "",
  "comments": "flag is here",
  "declarations": [],
  "spell": "16:80-16:81|1935187987660993811|3|2",
  "extent": "16:76-16:81|1935187987660993811|3|0",
  "type": 52,
  "uses": [],
  "kind": 13,
  "storage": 0
},

clang -fparse-all-comments 会把非Doxygen注释也嵌入AST,注释暗示了我们应该找和它类似的变量。 spell 差不多表示spelling SourceRange,第80列很奇怪。写一段程序收集位于80列的其他单字符变量,按行号排序:

#include"indexer.h"

const char blob[] = ".ccls-cache/@home@flag@/fringe.cc.blob";

__attribute__((constructor)) void solve(){
  std::string content = *ReadContent(blob);
  auto file = ccls::Deserialize(SerializeFormat::Binary, blob, content, "", {});
  std::vector<std::pair<int, char>> wod;
  for (auto &[usr, v] : file->usr2var) {
    Maybe<Use> spell = v.def.spell;
    if (spell) {
      Position start = spell->range.start;
      if (start.column == 79)
        wod.emplace_back(start.line, v.def.detailed_name[4]);
    }
  }
  sort(wod.begin(), wod.end());
  for (auto t: wod)
    putchar(t.second);
  puts("");
  exit(0);
}

Makefile 指定编译选项和链接选项,除了LLVM只有rapidjson一个依赖了。

CCLS := $(HOME)/Dev/Util/ccls
LLVM := $(HOME)/Dev/llvm

LDFLAGS := -shared
CXXFLAGS := -std=c++17 -fPIC -g
CXXFLAGS += -I$(CCLS)/src -I$(CCLS)/third_party -I$(CCLS)/third_party/rapidjson/include
CXXFLAGS += -I$(LLVM)/include -I$(LLVM)/Release/include
CXXFLAGS += -I$(LLVM)/tools/clang/include -I$(LLVM)/Release/tools/clang/include

solve.so: solve.cc
	$(LINK.cc) $^ -o $@

编译成 ccls.so ,让 ccls 吐出flag:

% LD_PRELOAD=./ccls.so ~/Dev/Util/ccls/Debug/ccls
blesswodwhoisinhk

这只是这人用的id的一个子串,他教育我要多做Codeforces,是很好玩的(可惜我依然这么菜,呜呜:sob::sob::crying_cat_face::crying_cat_face:)。

把same-fringe problem写成coroutine形式也是为了纪念一个去New York City的同学,他在Stanford读研期间,给一门课当助教时曾让我校对一个课程实验Cooperative User-Level Threads。

#include <iostream>
#include <vector>
#include <ucontext.h>
using namespace std;

struct TreeNode {
  int val;
  TreeNode *left;
  TreeNode *right;
};

struct Co {
  ucontext_t c;
  char stack[8192];
  TreeNode *ret;
  Co(ucontext_t *link, void (*f)(Co *, TreeNode *), TreeNode *root) {     {int b; /* flag is here */}
    getcontext(&c);                                                       {int l;}
    c.uc_stack.ss_sp = stack;                                             {int e;}
    c.uc_stack.ss_size = sizeof stack;                                    {int s;}
    c.uc_link = link;                                                     {int s;}
    makecontext(&c, (void(*)())f, 2, this, root);
  }
  void yield(TreeNode *x) {                                               {int w;}
    ret = x;                                                              {int o;}
    swapcontext(&c, c.uc_link);                                           {int d;}
  }
};

void dfs(Co *c, TreeNode *x) {                                            {int w;}
  if (!x) return;                                                         {int h;}
  if (!x->left && !x->right) c->yield(x);                                 {int o;}
  dfs(c, x->left);                                                        {int i;}
  dfs(c, x->right);                                                       {int s;}
}

class Solution {
public:
  bool leafSimilar(TreeNode *root1, TreeNode *root2) {                    {int i;}
    ucontext_t c;                                                         {int n;}
    Co c2(&c, dfs, root2), c1(&c2.c, dfs, root1);                         {int h;}
    do {                                                                  {int k;}
      c1.ret = c2.ret = nullptr;
      swapcontext(&c, &c1.c);
    } while (c1.ret && c2.ret && c1.ret->val == c2.ret->val);
    return !c1.ret && !c2.ret;
  }
};

void insert(TreeNode **x, TreeNode &y) {
  while (*x)
    x = y.val < (*x)->val ? &(*x)->left : &(*x)->right;
  *x = &y;
}

int main() {
  TreeNode xs[] = {{3},{1},{5},{0},{2},{4},{6}};
  TreeNode ys[] = {{5},{3},{6},{1},{4},{0},{2}};
  TreeNode zs[] = {{3},{1},{5},{0},{2},{6}};
  TreeNode *tx = nullptr, *ty = nullptr, *tz = nullptr;
  for (auto &x: xs) insert(&tx, x);
  for (auto &y: ys) insert(&ty, y);
  for (auto &z: zs) insert(&tz, z);
  Solution s;
  cout << s.leafSimilar(tx, ty) << endl;
  cout << s.leafSimilar(tx, tz) << endl;
}

假如你用clang trunk (>=7),ccls可以检索macro replacement-list中的引用。某些限定条件下template instantiation得到的引用也能索引。

代码

https://github.com/MaskRay/RealWorldCTF-2018-ccls-fringe

ccls的xref功能可以看 https://github.com/MaskRay/ccls/wiki/Emacs 里的截图。Vim/NeoVim用户也强烈建议看看Emacs能达到什么效果。最近也加了一个vscode-ccls,但我不用VSCode因此没有精力维护。 有更多精力的话可以帮我支持下 https://github.com/autozimu/LanguageClient-neovim/issues/454


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

平台转型

平台转型

陈威如、王诗一、余卓轩(统筹) / 中信出版社 / 2016-1-10 / 58

《平台战略》续篇,陈威如等关于企业平台转型最新力作! 平台带来的商业革命已改写了现在及未来的企业生存规则,而这股浪潮已经从互联网行业漫延到了其他多种行业之中!如果说,过去10 年是平台商业模式在互联网行业的爆发期,那未来10 年,将是平台商业模式在传统行业转型应用上的黄金时代。 平台思维不再是互联网行业的专用词,它可以用来解构价值链,可以被运用到组织架构的设计中,更能够帮助企业升级竞争......一起来看看 《平台转型》 这本书的介绍吧!

MD5 加密
MD5 加密

MD5 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试