Real World CTF 2018 ccls-fringe命题报告

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

内容简介:上周日给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


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

查看所有标签

猜你喜欢:

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

豆瓣,流行的秘密

豆瓣,流行的秘密

黄修源 / 机械工业出版社 / 2009-9 / 29.00

380万人为何会齐聚豆瓣? HIN1和SARS是如何传播扩散开的? 贾君鹏何以快速窜红网络? 通过创新扩散的理论的分析和说明,给出了所有这些问题的答案! 这本书从豆瓣的流行现象说开来,应用了创新扩散等传播学道理来解释了豆瓣如何流行起来,同时作者还同时用创新扩散的理论解释了为何会出现世界变平的现象,长尾理论,SARS病毒的高速传播等。 作者以前任豆瓣设计师的身份以自己亲......一起来看看 《豆瓣,流行的秘密》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

在线进制转换器
在线进制转换器

各进制数互转换器